File Coverage

blib/lib/Dependencies/Searcher.pm
Criterion Covered Total %
statement 44 170 25.8
branch 0 38 0.0
condition 0 27 0.0
subroutine 15 26 57.6
pod 11 11 100.0
total 70 272 25.7


line stmt bran cond sub pod time code
1             package Dependencies::Searcher;
2              
3 2     2   8900 use 5.010;
  2         4  
4 2     2   1226 use Data::Printer;
  2         52783  
  2         10  
5 2     2   209 use feature qw(say);
  2         3  
  2         156  
6             # Be careful, even if the Module::Corelist module is available since v5.8.9
7             # the is_core() method is only available since 2.99 module's version :)
8             # http://neilb.org/2013/09/21/adding-is-core.html
9 2     2   4540 use Module::CoreList;
  2         66076  
  2         41  
10 2     2   2108 use Module::Version 'get_version';
  2         147564  
  2         98  
11 2     2   895 use autodie;
  2         21914  
  2         8  
12 2     2   8106 use Moose;
  2         571296  
  2         10  
13 2     2   9765 use IO::File; # This comment creates a bug
  2         10686  
  2         193  
14 2     2   9 use File::HomeDir;
  2         2  
  2         72  
15 2     2   855 use Version::Compare;
  2         444  
  2         43  
16 2     2   768 use Path::Class;
  2         35256  
  2         89  
17 2     2   882 use ExtUtils::Installed;
  2         6845  
  2         56  
18 2     2   815 use File::Next;
  2         2566  
  2         46  
19 2     2   948 use PPI;
  2         168490  
  2         67  
20 2     2   12 use Term::ANSIColor;
  2         3  
  2         3835  
21             # For test only during dev
22             #use Dependencies::Searcher;
23              
24             our $VERSION = '0.066_004';
25              
26             =head1 NAME
27              
28             Dependencies::Searcher - Search for modules used or required by a
29             distribution.
30              
31             =cut
32              
33             =head1 SYNOPSIS
34              
35             use Dependencies::Searcher;
36              
37             my $searcher = Dependencies::Searcher->new();
38             my @elements = $searcher->get_files();
39             my @uses = $searcher->get_modules($path, "use");
40             my @uniq_modules = $searcher->uniq(@uses);
41              
42             $searcher->dissociate(@uniq_modules);
43              
44             $searcher->generate_report($searcher->non_core_modules);
45              
46             # Prints to cpanfile
47             # requires 'Data::Printer', '0.35';
48             # requires Moose, '2.0602';
49             # requires IPC::Cmd;
50             # requires Module::Version;
51             # ...
52              
53             Synopsis from Dependencies::Searcher::AckRequester
54              
55             # Places to search...
56             my @path = ("./lib", "./Makefile.PL", "./script");
57              
58             # Params for Ack
59             my @params = ('--perl', '-hi', $pattern, @path);
60              
61             # Absolute path to the Ack binary
62             my $ack_path = $requester->get_path();
63              
64             # Build the command for IPC::Cmd
65             my $cmd_use = $requester->build_cmd(@params);
66              
67             # Execute the command and retrieve the output
68             my @moduls = $requester->search($cmd_use);
69              
70             =cut
71              
72             =head1 DESCRIPTION
73              
74             Maybe you don't want to have to list all the dependencies of your Perl
75             application by hand and want an automated way to build it. Maybe you
76             forgot to do it for a long time ago. Or just during a short period.
77             Anyway, you've add lots of CPAN modules. L<Carton|Carton> is here to help you
78             manage dependencies between your development environment and
79             production, but how to keep track of the list of modules you will pass
80             to L<Carton|Carton>?
81              
82             Even if it is a no brainer to keep track of this list by adding it by
83             hand, it can be much better not to have to do it.
84              
85             You will need a tool that will check for any I<requires> or I<use> in
86             your module package, and report it into a file that could be used as an
87             input L<Carton|Carton> cpanfile. Any duplicated entry will be removed and
88             modules versions will be checked and made available. Core modules will be
89             ommited because you don't need to install them (except in some special
90             case, see C<dissociate()> documentation).
91              
92             This project has begun because it has happened to me, and I don't want
93             to search for modules to install by hand, I just want to run a simple
94             script that update the list in a convenient way. It was much more
95             longer to write the module than to search by hand so I wish it could
96             be useful for you now.
97              
98             This module is made to search dependencies for I<installed
99             distributions>, it is not supposed to manage anything else.
100              
101             =cut
102              
103             =head1 WHY ISN'T IT JUST ANOTHER MODULE::SCANDEPS ?
104              
105             Module::ScanDeps is a bi-dimentional recursive scanner: it features
106             dependencies and directories recursivity.
107              
108             Dependencies::Searcher only found direct dependencies, not
109             dependencies of dependencies, it scans recursively directories but not
110             dependencies..
111              
112             These direct dependencies are passed to the Perl toolchain (cpanminus)
113             that will take care of any recursive dependencies.
114              
115             =cut
116              
117             # Init parameters
118             has 'non_core_modules' => (
119             traits => ['Array'],
120             is => 'rw',
121             isa => 'ArrayRef[Str]',
122             default => sub { [] },
123             handles => {
124             add_non_core_module => 'push',
125             count_non_core_modules => 'count',
126             },
127             );
128              
129             has 'core_modules' => (
130             traits => ['Array'],
131             is => 'rw',
132             isa => 'ArrayRef[Str]',
133             default => sub { [] },
134             handles => {
135             add_core_module => 'push',
136             count_core_modules => 'count',
137             },
138             );
139              
140             has 'full_path' => (
141             is => 'rw',
142             isa => 'Str',
143             );
144              
145              
146             sub get_modules {
147             # @path contains files and directories
148 0     0 1   my ($self, $pattern, @path) = @_;
149              
150 0           say("Search pattern : " . $pattern);
151              
152 0           my @moduls = $self->search($pattern, @path);
153 0           say("Found $pattern modules : " . @moduls);
154              
155 0 0         if ( defined $moduls[0]) {
156 0 0 0       if ($moduls[0] =~ m/^use/ or $moduls[0] =~ m/^require/) {
157 0           return @moduls;
158             } else {
159             # Not really useful since we don't use ack no more
160 0           die "Failed to retrieve modules with Ack";
161             }
162             } else {
163 0           say "No use or require found !";
164             }
165             }
166              
167             sub get_files {
168 0     0 1   my $self = shift;
169             # Path::Class functions allows a more portable module
170 0           my $lib_dir = dir('lib');
171 0           my $make_file = file('Makefile.PL');
172 0           my $script_dir = dir('script');
173             # note1 t/ is ignored
174             # note2 any type of interesting file or dir should be listed here
175              
176 0           my @structure;
177              
178 0 0         if (-d $lib_dir) {
179 0           $structure[0] = $lib_dir;
180             } else {
181             # TODO : TEST IF THE PATH IS OK ???
182             # What can you do if a module don't have a lib/ dir ?
183 0           die "Don't look like we are working on a Perl module";
184             }
185              
186 0 0         if (-f $make_file) {
187 0           $structure[1] = $make_file;
188             }
189              
190 0 0         if (-d $script_dir) {
191 0           $structure[2] = $script_dir;
192             }
193              
194 0           return @structure;
195             }
196              
197             # Generate a "1" when merging if one of both is empty
198             # Will be clean in avoid_superfluous() method
199             sub merge_dependencies {
200 0     0 1   my ($self, @uses, @requires) = @_;
201 0           my @merged_dependencies = (@uses, @requires);
202 0           say("Merged use and require dependencies");
203 0           return @merged_dependencies;
204             }
205              
206             # Remove special cases that aren't need at all
207             sub avoid_superfluous {
208 0     0 1   my ($self, @merged) = @_;
209 0           my @real_modules;
210             # Push everything except the special cases that are totally useless
211 0           foreach my $module ( @merged ) {
212 0 0 0       push(@real_modules, $module) unless
      0        
      0        
      0        
      0        
      0        
      0        
213              
214             $module =~ m/say/
215              
216             # Describes a minimal Perl version
217             # BUG #76, see above
218             or $module =~ m/^use\s[0-9]\.[0-9]+?/
219             or $module =~ m/^use\sautodie?/
220             or $module =~ m/^use\swarnings/
221             # Kind of bug generated by merge_dependencies() when there is
222             # only one array to merge
223             or $module =~ m/^1$/
224             or $module =~ m/^use\sDependencies::Searcher/
225             # Bug #76, a regex in this module created a match ("\s" module) in the
226             # patterns search
227             # https://git.framasoft.org/smonff/dependencies-searcher/issues/76
228             or $module =~ m/\/\^use\\s/
229             or $module =~m/^use\s\\s/;
230             }
231 0           return @real_modules;
232             }
233              
234             # Clean correct lines that can't be removed
235             sub clean_everything {
236 0     0 1   my ($self, @dirty_modules) = @_;
237 0           my @clean_modules = ();
238              
239 0           foreach my $module ( @dirty_modules ) {
240              
241 0           say("Dirty module : " . $module);
242              
243             # remove the 'use' and the space next
244 0           $module =~ s{
245             use \s
246             }
247             {}xi; # Empty subtitution
248              
249             # remove the require, quotes and the space next
250             # but returns the captured module name (non-greedy)
251             # i = not case-sensitive
252 0           $module =~ s{
253             requires \s
254             '
255             (.*?)
256             '
257             }{$1}xi; # Note -> don't insert spaces here
258              
259             # Remove the ';' at the end of the line
260 0           $module =~ s/ ; //xi;
261              
262             # Remove any qw(xxxxx xxxxx) or qw[xxx xxxxx]
263             # '\(' are for real 'qw()' parenthesis not for grouping
264             # Also removes empty qw()
265              
266             # With spaces and parenthesis e.g. qw( foo bar )
267 0           $module =~ s{
268             \s qw
269             \(
270             (\s*[A-Za-z]+(\s*[A-Za-z]*))*\s*
271             \)
272             }{}xi;
273              
274             # Without spaces, with parenthesis e.g. qw(foo bar) and optionnal [method_names
275 0           $module =~ s{
276             \s qw
277             \(
278             ([A-Za-z]+(_[A-Za-z]+)*(\s*[A-Za-z]*))*
279             \)
280             }{}xi;
281              
282             # With square brackets e.g. qw[foo bar] and optionnal [method_names]
283 0           $module =~ s{
284             \s qw
285             \[
286             ([A-Za-z]+(_[A-Za-z]+)*(\s*[A-Za-z]*))*
287             \]
288             }
289             {}xi; # Empty subtitution
290             # With spaces and parenthesis e.g. qw/ foo bar /
291 0           $module =~ s{
292             \s qw
293             \/
294             (\s[A-Za-z]+(_[A-Za-z]+)*(\s*[A-Za-z]*))*\s
295             \/
296             }
297             {}xi; # Empty subtitution
298              
299             # Remove method names between quotes (those that can be used
300             # without class instantiation)
301 0           $module =~ s{
302             \s
303             '
304             [A-Za-z]+(_[A-Za-z]+)*
305             '
306             }
307             {}xi; # Empty subtitution
308              
309             # Remove dirty bases and quotes.
310             # This regex that substitute My::Module::Name
311             # to a "base 'My::Module::Name'" by capturing
312             # the name in a non-greedy way
313 0           $module =~ s{
314             base \s
315             '
316             (.*?)
317             '
318             }
319             {$1}xi;
320              
321             # Remove some warning sugar
322 0           $module =~ s{
323             ([a-z]+)
324             \s FATAL
325             \s =>
326             \s 'all'
327             }
328             {$1}xi;
329              
330             # Remove version numbers
331             # See "a-regex-for-version-number-parsing" :
332             # http://stackoverflow.com/questions/82064/
333 0           $module =~ s{
334             \s
335             (\*|\d+(\.\d+)
336             {0,2}
337             (\.\*)?)$
338             }
339             {}x;
340              
341             # Remove configuration stuff like env_debug => 'LM_DEBUG' but
342             # the quoted words have been removed before
343 0           $module =~ s{
344             \s
345             ([A-Za-z]+(_[A-Za-z]+)*( \s*[A-Za-z]*))*
346             \s
347             =>
348             }
349             {}xi;
350              
351              
352 0           say("Clean module : " . $module);
353 0           push @clean_modules, $module;
354             }
355 0           return @clean_modules;
356             }
357              
358              
359             sub uniq {
360 0     0 1   my ($self, @many_modules) = @_;
361 0           my @unique_modules = ();
362 0           my %seen = ();
363 0           foreach my $element ( @many_modules ) {
364 0 0         next if $seen{ $element }++;
365 0           say("Uniq element added : " . $element);
366 0           push @unique_modules, $element;
367             }
368 0           return @unique_modules;
369             }
370              
371             sub dissociate {
372 0     0 1   my ($self, @common_modules) = @_;
373              
374 0           foreach my $nc_module (@common_modules) {
375              
376 0           my $core_list_answer = Module::CoreList::is_core($nc_module);
377              
378 0 0 0       if (
379             # "$]" is Perl version
380             (exists $Module::CoreList::version{ $] }{"$nc_module"})
381             or
382             # In case module don't have a version number
383             ($core_list_answer == 1)
384             ) {
385              
386             # A module can be in core but the wanted version can be
387             # more fresh than the core one...
388             # Return the most recent version
389 0           my $mversion_version = get_version($nc_module);
390             # Return the corelist version
391 0           my $corelist_version = $Module::CoreList::version{ $] }{"$nc_module"};
392              
393 0           say("Mversion version : " . $mversion_version);
394 0           say("Corelist version : " . $corelist_version);
395              
396             # Version::Compare warns about versions numbers with '_'
397             # are 'non-numeric values'
398 0           $corelist_version =~ s/_/./;
399 0           $mversion_version =~ s/_/./;
400              
401             # It's a fix for this bug
402             # https://github.com/smonff/dependencies-searcher/issues/25
403             # Recent versions of corelist modules are not include in
404             # all Perl versions corelist
405 0 0         if (&Version::Compare::version_compare(
406             $mversion_version, $corelist_version
407             ) == 1) {
408 0           say(
409             $nc_module . " version " . $mversion_version .
410             " is in use but " .
411             $corelist_version .
412             " is in core list"
413             );
414 0           $self->add_non_core_module($nc_module);
415 0           say(
416             $nc_module .
417             " is in core but has been added to non core " .
418             "because it's a fresh core"
419             );
420 0           next;
421             }
422              
423             # Add to core_module
424              
425             # The "Moose" trait way
426             # http://metacpan.org/module/Moose::Meta::Attribute::Native::Trait::Array
427 0           $self->add_core_module($nc_module);
428 0           say($nc_module . " is core");
429              
430             } else {
431 0           $self->add_non_core_module($nc_module);
432 0           say($nc_module . " is not in core");
433             }
434             }
435             }
436              
437             # Open a file handle to > cpanfile
438             sub generate_report {
439              
440 0     0 1   my $self = shift;
441              
442             #
443             # TODO !!! Check if the module is installed already with
444             # ExtUtils::Installed. If it it not, cry that
445             # Dependencies::Searcher is designed to be used in the complete env
446             #
447              
448 0 0         open my $cpanfile_fh, '>', 'cpanfile' or die "Can't open cpanfile : $:!";
449              
450 0           foreach my $module_name ( @{$self->non_core_modules} ) {
  0            
451              
452 0           my $version = get_version($module_name);
453              
454             # if not undef
455 0 0         if ($version) {
456 0           say("Module + version : " . $module_name . " " . $version);
457              
458             # Add the "requires $module_name\n" to the next line of the file
459 0           chomp($module_name, $version);
460              
461 0 0         if ($version =~ m/[0-9]\.[0-9]+/ ) {
462 0           say $cpanfile_fh "requires '$module_name', '$version';";
463             } # else : other case ?
464              
465             } else {
466 0           say("Module + version : " . $module_name);
467 0           say $cpanfile_fh "requires '$module_name';";
468             }
469              
470             }
471              
472 0           close $cpanfile_fh;
473 0           say("File has been generated and is waiting for you");
474             }
475              
476              
477             # under rewriting since we removed Dependencies::Searcher::AckRequester
478             sub search {
479 0     0 1   my ($self, $pattern, @paths) = @_;
480              
481 0           my @modules;
482              
483 0           my $iter = File::Next::files(@paths);
484              
485             # Each path is a file in the chosen hierarchy
486 0           while ( defined ( my $path = $iter->() )) {
487              
488 0           my $namespace;
489 0           my $file = file($path);
490              
491             # We have to test that we don't include namespaces of the
492             # analyzed module
493 0           my $document = PPI::Document->new($file->stringify);
494             # Testing that the file is actually a module, not for example Makefile.PL
495 0           my $is_module = $document->find_first('PPI::Statement::Package');
496 0 0         if ($is_module) {
497 0           $namespace = $is_module->namespace;
498             }
499              
500 0           my @lines = $file->slurp;
501              
502 0           for my $line (@lines) {
503              
504             # if ( $line =~ /use\\s/m ) {
505             # say "$line !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
506             #}
507              
508             # Remove carriage return
509 0           chomp $line;
510             # Remove tabs
511 0           $line =~ s/^\t+//;
512              
513 0 0         if ($is_module) {
514             # We jump to the next line if we found the analyzed
515             # package in the array of lines
516 0 0         if ($line =~ /use $namespace/ ) {
517 0           $self->coucou("Module namespace ($line) has been ommited ")
518             }
519 0 0         next if $line =~ $namespace;
520             }
521              
522 0 0         if ($line =~ /^$pattern\s/ ) {
523 0           say($line);
524              
525             # Clean the result
526 0           $line = $self->rm_comments($line);
527              
528 0           push(@modules, $line);
529             }
530             }
531             }
532              
533             # TODO retrieve modules from Makefile.PL (it cannot be based on
534             # the use of a "pattern" in this case)
535              
536 0           p @modules;
537 0           return @modules;
538             }
539              
540             # It could be a simplist implementation, but I didn't find something
541             # more clever. Comments appreciated.
542             sub rm_comments {
543              
544 0     0 1   my ($self, $dirt) = @_;
545              
546             # Case #1: "use" declaration line with a comment after
547             # The regex add the terminal semicolon at the end of the line to
548             # make the difference between comments and code, because "use" is
549             # a word that you can find often in a POD section, more much in
550             # the beginning of line than you could think
551 0 0         if ( $dirt =~ /#.+/ ) {
552 0           say("Entered rm_comment for $dirt");
553 0           $dirt =~ s/#(.*)//;
554             # Delete spaces
555 0           $dirt =~ s/\s*//xi;
556             }
557              
558             # $pattern = "$pattern" . qr/.+;$/; # <= This is an horrible bug,
559             # because we could have a
560             # comment here
561              
562             # Case #2 pod
563             # TODO
564              
565              
566 0           my $clean = $dirt;
567              
568 0           return $clean;
569             }
570              
571             sub coucou {
572 0     0 1   my ($self, $thing, $color) = @_;
573 0 0         if (not $color) {
574 0           $color = 'red';
575             }
576 0           say(color("$color"), $thing);
577             }
578              
579              
580             1;
581              
582             __END__
583              
584             =pod
585              
586             =head1 SUBROUTINES/METHODS
587              
588             =head2 get_files()
589              
590             C<get_files()> returns an array containing which file or directories has
591             been found in the current root distribution directory. We suppose it
592             can find dependancies in 3 different places :
593              
594             =over 2
595              
596             =item * files in C<lib/> directory, recursively
597              
598             =item * C<Makefile.PL>
599              
600             =item * C<script/> directory, i.e. if we use a Catalyst application
601              
602             =item * maybe it should look in C<t/> directory (todo)
603              
604             =back
605              
606             If the C<lib/> directory don't exist, the program die because we
607             consider we are not into a plain old Perl Module.
608              
609             This is work in progress, if you know other places where we can find
610             stuff, please report a bug.
611              
612             =cut
613              
614             =head2 get_modules("pattern", @elements)
615              
616             You must pass a pattern to search for, and the elements (files or
617             directories) where you want to search (array of strings from C<get_files()>).
618              
619             These patterns should be C<^use> or C<^require>.
620              
621             Then, the search() subroutine will be used to retrieve modules names
622             into lines containing patterns and return them into an array
623             (containing also some dirt).
624              
625             =cut
626              
627             =head2 merge_dependencies(@modules, @modules)
628              
629             Simple helper method that will merge C<use> and C<require> arrays if you
630             search for both. Return an uniq array. It got a little caveat, see
631             CAVEATS.
632              
633             =cut
634              
635             =head2 avoid_superfluous(@modules)
636              
637             Move dependencies lines from an array to an another unless it is
638             considered as a "superfluous" unneccessary case : minimal Perl versions, C<use autodie>,
639             C<use warnings>. These stuff has to be B<removed>, not cleaned. Return a I<real
640             modules> array (I<real interresting> modules).
641              
642             =cut
643              
644             =head2 clean_everything(@modules)
645              
646             After removing irrelevant stuff, we need to B<clean> what is leaving
647             and is considered as being crap (not strictly <CName::Of::Module>) but
648             needs some cleaning. We are going to remove everything but the module
649             name (even version numbers).
650              
651             This code section is well commented (because it is regex-based) so,
652             please refer to it directly.
653              
654             It returns an array of I<clean modules>.
655              
656             =cut
657              
658             =head2 uniq(@modules)
659              
660             Make each array element uniq, because one dependency can be found many
661             times. Return an array of unique modules.
662              
663             =cut
664              
665             =head2 dissociate(@modules)
666              
667             Dissociate I<core> / I<non-core> modules using the awesome
668             C<Module::Corelist::is_core method>, that search in the current Perl
669             version if the module is from Perl core or not. Note that results can
670             be different according to the environment.
671              
672             More, B<you can have two versions of the same module installed on your
673             environment> (even if you use L<local::lib|local::lib> when you
674             install a recent version of a file that has been integrated into Perl
675             core (this version hasn't necessary been merged into core).
676              
677             So C<dissociate()> checks both and compares it, to be sure that the found core
678             module is the "integrated" version, not a fresh one that you have
679             installed yourself. If it is fresh, the module is considered as a I<non-core>.
680              
681             This method don't return anything, but it stores found dependencies on the two
682             C<core_modules> and C<non_core_modules> L<Moose|Moose> attributes arrays.
683              
684             =cut
685              
686             =head2 generate_report()
687              
688             Generate the C<cpanfile> for L<Carton|Carton>, based on data contained into
689             C<core_modules> and C<non_core_modules> attributes, with optionnal
690             version number (if version number can't be found, dependency name is
691             print alone).
692              
693             Generate a hash containing the modules could be achieved. Someday.
694              
695             =cut
696              
697             =head2 get_path()
698              
699             Returns the L<ack> full path if installed. Set the C<full_path>
700             L<Moose> attribute that will be used by ICP::Cmd. It verify also that
701             L<Ack> is reachable or warns about it.
702              
703             =cut
704              
705             =head2 build_cmd(@params)
706              
707             C<build_cmd()> takes as parameter all the arguments Ack will
708             need. L<Dependencies::Searcher> defines it like this :
709              
710             =over 4
711              
712             =item * C<--perl> : tells to search in Perl like files (C<*.pm>, C<*.pl>, etc.)
713              
714             =item * C<-hi> : suppress the prefixing filename on output + ignore
715             case
716              
717             =item * C<$pattern> : must be passed from your implementation
718              
719             =item * C<@path> : files and directories where L<ack> will go
720              
721             All these params are merged in an only array reference that is returned for
722             later use with L<IPC::Cmd>.
723              
724             =back
725              
726             =cut
727              
728             =head2 ack($params_array_ref)
729              
730             Execute the L<IPC::Cmd> command that calls C<ack> and returns an array of
731             potentially interesting lines, containing dependencies names but some
732             crap inside too.
733              
734             =cut
735              
736             =head2 rm_comments($line_that_should_be_cleaned_of_any_comment)
737              
738             Supposed to remove any comment from a line.
739              
740             =cut
741              
742             =head2 coucou($tring, $color)
743              
744             Stupid DIY logger
745              
746             =cut
747              
748             =head1 CAVEATS
749              
750             =head2 Low Win32 / Cygwin support
751              
752             This module was'nt supposed to run under Win32 / Cygwin environments
753             because it was using non portable code with slashes. I hope this gets
754             better since it has been rewritten using L<Path::Class|Path::Class>
755             but it still need some testing.
756              
757             It also us-e Ack as a hack through a system command even if it was not
758             supposed to be used like that. Yes, this is dirty. Yes, I plan to change
759             things, even if Ack do the stuff proudly this way.
760              
761             Thanks to cpantesters.org community reports, things should go better and
762             better.
763              
764             =head2 Fun : some are able to do it using a one-liner
765              
766             Command Line Magic (@climagic) tweeted 4:17 PM on lun., nov. 25, 2013
767              
768             # Not perfect, but gives you a start on the Perl modules in use.
769             grep -rh ^use --include="*.pl" --include="*.pm" . | sort | uniq -c
770              
771             See original Tweet https://twitter.com/climagic/status/404992356513902592
772              
773             Though, it don't really work, that's why I made this module.
774              
775             =cut
776              
777             =head1 BUGS
778              
779             Please report any bugs or feature requests to
780             C<bug-dependencies-searcher at rt.cpan.org>, or through the web
781             interface at
782             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Dependencies-Searcher>.
783             I will be notified, and then you'll automatically be notified of
784             progress on your bug as I make changes.
785              
786             =head1 REPOSITORY
787              
788             L<https://git.framasoft.org/smonff/dependencies-searcher>
789              
790             =head1 TODOs
791              
792             Most of the time, todos and features are on Github and Questub.
793             See https://github.com/smonff/dependencies-searcher/issues
794              
795             =head1 SUPPORT
796              
797             You can find documentation for this module with the perldoc command.
798              
799             perldoc Dependencies::Searcher
800              
801             You can also look for information at:
802              
803             See https://github.com/smonff/dependencies-searcher/
804              
805             =over 2
806              
807             =item * RT: CPAN's request tracker (report bugs here)
808              
809             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Dependencies-Searcher>
810              
811             =item * AnnoCPAN: Annotated CPAN documentation
812              
813             L<http://annocpan.org/dist/Dependencies-Searcher>
814              
815             =item * CPAN Ratings
816              
817             L<http://cpanratings.perl.org/d/Dependencies-Searcher>
818              
819             =item * Search CPAN
820              
821             L<http://search.cpan.org/dist/Dependencies-Searcher/>
822              
823             =back
824              
825             =head1 AUTHOR
826              
827             smonff, C<< <smonff at gmail.com> >>
828              
829             =head1 CONTRIBUTORS
830              
831             =over
832              
833             =item * Nikolay Mishin (mishin) helps to make it more cross-platform
834              
835             =item * Alexandr Ciornii (chorny) advises on version numbers
836              
837             =back
838              
839             =cut
840              
841             =head1 ACKNOWLEDGEMENTS
842              
843             =over
844              
845             =item L<Module::Extract::Use|Module::Extract::Use>
846              
847             Was the main inspiration for this one. First, I want to use it for my needs
848             but it was not recursive...
849              
850             See L<https://metacpan.org/module/Module::Extract::Use>
851              
852             =item L<Module::CoreList|Module::CoreList>
853              
854             What modules shipped with versions of perl. I use it extensively to detect
855             if the module is from Perl Core or not.
856              
857             See L<http://perldoc.perl.org/Module/CoreList.html>
858              
859             =item L<http://beyondgrep.com/|Ack>
860              
861             Ack gives me the wish to try to write this module. It was pure Perl so
862             I've choose it because it was possible to install it through CPAN
863             during the distribution installation process. Even if Ack was not
864             meant for being used programatically, this hacked use of Ack did the
865             job during the first part of this module's life. These dready parts
866             (use of Ack with IPC::Cmd) have been removed since.
867              
868             =back
869              
870             See also :
871              
872             =over 2
873              
874             =item * https://metacpan.org/module/Perl::PrereqScanner
875              
876             =item * http://stackoverflow.com/questions/17771725/
877              
878             =item * https://metacpan.org/module/Dist::Zilla::Plugin::AutoPrereqs
879              
880             =back
881              
882             =head1 LICENSE AND COPYRIGHT
883              
884             Copyright 2013-2016 Sebastien Feugere.
885              
886             This program is free software; you can redistribute it and/or modify it
887             under the terms of either: the GNU General Public License as published
888             by the Free Software Foundation; or the Artistic License.
889              
890             See L<http://dev.perl.org/licenses/> for more information.
891              
892              
893             =cut
894              
895