Running the Catalyst internal server, located at scripts/MyApp_server.pm, I receive the following error. Is there any one who can help me in this regard?
I have not changed any of the files created by catalyst.pl. I just have run the catalyst.pl MyApp and then run scripts/MyApp_server.pl -r for testing whether Catalyst works or not. This is the only things I have done!
I have reinstalled Catalyst and its dependent modules several times by using either yum and cpan. But it doesn't work again.
Thanks!
THE ERROR MESSAGE:
Can't use an undefined value as a HASH reference at /usr/local/share/perl5/Catalyst.pm line 2681.
BEGIN failed--compilation aborted at /home/Ali/Lab/WEB/catalyst/MyApp3/script/../lib/MyApp3.pm line 20.
Compilation failed in require at /usr/local/lib/perl5/Class/MOP/Method/Wrapped.pm line 50
The codes around line 2681 in /usr/local/share/perl5/Catalyst.pm are as below:
sub setup_home {
my ( $class, $home ) = #_;
if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
$home = $env;
}
$home ||= Catalyst::Utils::home($class);
if ($home) {
#I remember recently being scolded for assigning config values like this
$class->config->{home} ||= $home; # THIS IS LINE 2681
$class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
}
}
The content of the lib/MyApp.pm is as below:
package MyApp;
use Moose;
use namespace::autoclean;
use Catalyst::Runtime 5.80;
# Set flags and add plugins for the application
#
# -Debug: activates the debug mode for very useful log messages
# ConfigLoader: will load the configuration from a Config::General file in the
# application's home directory
# Static::Simple: will serve static files from the application's root
# directory
use Catalyst qw/
-Debug
ConfigLoader
Static::Simple
/;
extends 'Catalyst';
our $VERSION = '0.01';
$VERSION = eval $VERSION;
# Configure the application.
#
# Note that settings in myapp.conf (or other external
# configuration file that you set up manually) take precedence
# over this when using ConfigLoader. Thus configuration
# details given here can function as a default configuration,
# with an external configuration file acting as an override for
# local deployment.
__PACKAGE__->config(
name => 'MyApp',
# Disable deprecated behavior needed by old applications
disable_component_resolution_regex_fallback => 1,
);
# Start the application
__PACKAGE__->setup();
=head1 NAME
MyApp - Catalyst based application
=head1 SYNOPSIS
script/myapp_server.pl
=head1 DESCRIPTION
[enter your description here]
=head1 SEE ALSO
L<MyApp::Controller::Root>, L<Catalyst>
=head1 AUTHOR
Ali Basirat
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
1;
This isn't a definitive answer, but hopefully will help a little.
You've either got an undefined $class or $class->config (more likely), although how I can't say. Perhaps the ConfigLoader hasn't worked.
Re-installing things blindly seldom helps and the problem could be due to any module in the dependency list. If there was a specific problem installing a module then there would have been an error and we could have worked on that.
So - using yum install cpanm and local::lib - I'm not sure what the packages are called on Red Hat, but it should be easy enough to find out.
OK - now create a new directory somewhere suitable.
mkdir /home/Devt/catalyst_test
cd /home/Devt/catalyst_test
eval $(perl -Mlocal::lib=./perllib)
echo $PERL5LIB
# You should see your current directory mentioned in PERL5LIB
cpanm Catalyst
cpanm Catalyst::Helper
catalyst.pl MyApp
cd MyApp/
perl Makefile.PL
./script/myapp_server.pl
# Opens up a server on port 3000
What local::lib is doing is setting up the paths to install everything locally (in perllib) - you can see the environment variables it sets up by running it without the eval.
perl -Mlocal::lib=./perllib
See the docs for how to add it to a bash login script. I just redirect the output to a file and source it when I'm working on a project (I use one perllib per project).
Then, cpanm is smart enough to use this local directory to install all the bits you need.
If this doesn't work, the problem is probably due to something you've manually installed in /usr/local/. Take a backup of the various perl-related lib dirs in /usr/local/ and then clean them out. Run cpanm again (checking local::lib paths are setup first) and see if the versions it downloads work.
The above should work - it's exactly what I did 10 minutes ago.
The whole idea of this is to create a separate installation of all your perl libraries for this project - that way if you upgrade anything it only affects the current installation.
Related
I am using the Dist::Zilla module to release and test my module. I am also using Perlbrew. When I run a script using perlbrew that includes my module, the script runs fine:
use strict;
use My::Module;
However, whenever I run dzil test, on a test that just tries to include my module:
#!perl -T
use strict;
use warnings FATAL => 'all';
use Test::More;
plan tests => 1;
BEGIN {
use_ok( 'My::Module' ) || print "Bail out!\n";
}
diag( "Testing My::Module $My::Module::VERSION, Perl $], $^X" );
It fails with this error saying that it can't find the module Mouse (which my module includes):
Error: Can't locate Mouse.pm in #INC (you may need to install the Mouse module) (#INC contains:
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/lib
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/arch
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18
/Network/Library/Perl/5.18/darwin-thread-multi-2level
/Network/Library/Perl/5.18
/Library/Perl/Updates/5.18.2/darwin-thread-multi-2level
/Library/Perl/Updates/5.18.2
/System/Library/Perl/5.18/darwin-thread-multi-2level
/System/Library/Perl/5.18
/System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.18) at
/Users/user/github/My/Module/.build/HoKOnIQGYr/blib/lib/My/Module.pm line 4.
It says that it cannot find Mouse.pm, which I know is located at
/Users/user/perl5/lib/perl5/darwin-2level
I see that for some reason that directory is not located in #INC, which is interesting because if I run this command to print out all the directories in #INC:
perl -e 'print "$_\n" for #INC'
I get:
/Users/user/perl5/lib/perl5/darwin-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/darwin-2level
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0/darwin-2level
/Users/user/perl5/perlbrew/perls/perl-5.16.0/lib/5.16.0
.
So when I run perl on the command line then the darwin-2level directory is present in #INC, but whenever I run dzil test it is not. This might not have much to do with Dist::Zilla, since I think Dist::Zilla just creates Makefile.PL and runs make test for you. Could this be because for testing an older version of perl is being required? Like so:
use 5.006;
But even so, some Perlbrew directories are present in #INC during the test such as
/Users/user/perl5/lib/perl5/darwin-thread-multi-2level
Does anyone know how I can make it so I can use the Mouse installation in my perl directory instead of installing a systemwide one? I had a previous error with another module that couldn't be found when I ran dzil test, and that module was in the same directory as Mouse. I was able to fix the issue by installing the module systemwide instead of locally in my home perl5 directory, but I'd prefer to use the Mouse installed by Perlbrew and not mess with my system perl if possible. I am using Perlbrew version 0.73.
You're trying to install it using the wrong perl since you're using dzil installed by a different perl than the one you want to use.
Furthermore, you shouldn't see any of the following in your perlbrewed perl's #INC:
/Users/user/perl5/lib/perl5/darwin-2level
/Users/user/perl5/lib/perl5
/opt/local/lib/perl5/vendor_perl/5.16.1/darwin-thread-multi-2level/ (You perlbrewed perl isn't even threaded!!!)
Let's clean up your environment.
Unset env vars PERL5LIB, PERLLIB, PERL5OPT, PERL_MM_OPT and PERL_MB_OPT. Permanently. Get rid of them in your login scripts, then unset them from the current shell or log back in. (Make a note of what they were as a backup.)
Clear cpan's configuration item makepl_arg. From within cpan,
o conf makepl_arg # Just to see its current value as a backup.
o conf makepl_arg ''
o conf commit
In particular, we want to remove anything that indicates an installation path, including INSTALL_BASE, PREFIX and LIB.
Clear cpan's configuration item mbuildpl_arg. From within cpan,
o conf mbuildpl_arg # Just to see its current value as a backup.
o conf mbuildpl_arg ''
o conf commit
In particular, we want to remove anything that indicates an installation path, including --install_base, --prefix and --lib.
Since you're there, do the following from within cpan:
o conf build_dir_reuse 0
o conf commit
This will restore the setting to its default, which will save you headaches if it was changed.
Install the dependencies.
cpan Dist::Zilla Mouse
At this point, executing which dzil should give
/Users/user/perl5/perlbrew/perls/perl-5.16.0/bin/dzil
If so, you should be good to go.
If not, do hash -r and try which dzil again. (This shouldn't be needed, but just to be sure.)
If still not, provide the output of the following commands:
echo "$PATH"
which cpan
head -n 3 "$( which cpan )"
echo 'o conf' | cpan | grep arg
which dzil
head -n 3 "$( which dzil )"
perl -V # Uppercase "V"
I am trying to figure out how to use Doxygen::Filter::Perl to generate documentation for Perl files. I am starting with a very simple file just to see if I can get it to work (test_doxygen.pl):
#! /usr/bin/env perl
#** #file test_doxygen.pl
# #brief Testing Doxygen using Doxygen::Filter::Perl
#
# Description of the purpose of this file
#
# #author Håkon Hægland (hakon.hagland#gmail.com)
#
# #bug No known bugs.
#
#*
#** #class main
# The main class
#*
use strict;
use warnings;
my $b = add_one(1);
#** #function public add_one ($par1)
# #brief A brief description of the function
#
# A detailed description of the function
# #params $par1 required A number
# #retval value Input value plus one1
#*
sub add_one {
my ($par1) = #_;
return $par1 + 1;
}
I then installed Doxygen::Filter::Perl and used the Doxyfile configuration file provided by the package maintainer at metacpan.org (the link is here)
and put it in the same directory as the script above. I changed one line in the Doxyfile: the value of the INPUT tag was changed from lib to the empty string, in order to only search the current directory for source files..
I am using Ubuntu 14.04, so I installed Doxygen with sudo apt-get install doxygen, (I also needed to install graphviz: sudo apt-get install graphviz) then I finally run
$ doxygen
from the terminal window. The generated HTML file doc/html/index.html contains documentation about the file and the author, but it does not contain any documentation for the add_one sub routine.
What am I missing here?
Update
Here is how the class view looks like in Chromium browser:
As seen, there is no reference/link to the add_one sub routine.
And here is the file view:
So the problem was with handling the "my" variable declaration. It set the value to be private: and doxygen never went back. I have added a line to Perl.pm to fix this and it should work for you now. Since you are working with pl files not pm files, I have also made changes to the Doxyfile, so you will want to get the new one from the distribution. I have published 1.71 to Github and CPAN and have tested it with your exact example.
I just posted a new version of Doxygen::Filter::Perl to Github and CPAN, version 1.70. This should fix the problems you were seeing.
I just looked at this and it seems to work with Doxygen (1.7.5.1), however, the newer version of Doxygen (1.8.9.1) does not seem to work well.
I cannot use %ENV var on my Perl script to use Oracle libs.
BEGIN {
$ORACLE_HOME = "/usr/lib/oracle/10.2.0.3/client64";
$LD_LIBRARY_PATH = "$ORACLE_HOME/lib";
$ORACLE_SID="prod";
$ENV{ORACLE_SID}=$ORACLE_SID;
$ENV{ORACLE_HOME}= $ORACLE_HOME;
$ENV{LD_LIBRARY_PATH}= $LD_LIBRARY_PATH;
};
If I print $ENV{'ORACLE_HOME'} and $ENV{'LD_LIBRARY_PATH'} all seems ok but, when I run my script I have the error:
install_driver(Oracle) failed: Can't load '/usr/local/lib64/perl5/auto/DBD/Oracle/Oracle.so' for module DBD::Oracle: libclntsh.so.10.1: cannot open shared object file: No such file or directory at /usr/lib64/perl5/DynaLoader.pm line 200.
at (eval 3) line 3
Compilation failed in require at (eval 3) line 3.
Perhaps a required shared library or dll isn't installed where expected
at persistence.perl line 22
Searching on web I saw that the correct way to set env vars on Perl is to use %ENV hash.
Exporting ORACLE_HOME and LD_LIBRARY_PATH through unix shell (export LD_LIBRARY_PATH=...) it works correctly. Any advice?
The LD_LIBRARY_PATH environment variable has to be set before your program starts — before perl itself is loaded. Changing it in BEGIN{} will affect new programs that you start, but it won't affect the loading of shared libraries — in this case (although I've never used the DBD::Oracle) you're loading an Oracle .so into the already-running program, so it's “too late” to change the LD_LIBRARY_PATH. The dynamic linker /lib/ld.so (or so) is started before perl, so by the time your script is compiled and BEGIN{} runs, it's already set up.
You could try to re-exec your script as its own successor or something*, but a short shell script is almost certainly going to be the simplest solution:
#!/bin/sh
export LD_LIBRARY_PATH=/usr/lib/oracle/10.2.0.3/client64/lib
export ORACLE_SID=prod
exec /usr/local/bin/your-db-program "$#"
*- this would be kinda crazy, but TIMTOWTDI:
eval {
use DBD::Oracle foo bar baz; …
};
if ($# =~ /install_driver\(Oracle\) failed/) {
$ENV{LD_LIBRARY_PATH} .= ':/usr/lib/oracle/10.2.0.3/client64/lib';
$ENV{ORACLE_SID} = 'prod';
warn "Restarting with LD_LIBRARY_PATH reset:\n\n$#\n";
exec { $0 } $0 => #ARGV;
}
I wrote a few test scripts to verify that the environment is being set when you change %ENV:
use strict;
use warnings;
use feature qw(say);
BEGIN {
my $foo = "bar-bar";
$ENV{FOO} = "$foo";
}
system qq(/bin/echo printing out \$FOO);
This prints out:
printing out bar-bar
which is what I expected.
I then tried this:
use strict;
use warnings;
use feature qw(say);
BEGIN {
my $foo = "bar-bar";
$ENV{FOO} = "$foo";
}
system qq(./test.sh);
and created a test.sh program that looks like this:
#! /bin/sh
echo This is what I got: $FOO;
In this case, my Perl script is running test.sh which prints out the value of the $FOO environment variable that was set in my Perl script. Running test.pl I get:
This is what I got bar-bar
This shows that not only is Perl setting the environment variables, but that it is also exporting those variables, so called shell scripts have access to them.
You can try a similar technique to verify that both LD_LIBRARY_PATH and ORACLE_HOME are being set before they're used. I suspect you'll find that this is indeed happening, but that your program still isn't working when you set %ENV.
This points to one conclusion: Setting the environment for LD_LIBRARY_PATH and ORACLE_HOME might be occurring too late by the time your Perl script starts. I believe the operating system examines LD_LIBRARY_PATH before Perl starts. I found this doing a search on LD_LIBRARY_PATH:
LD_LIBRARY_PATH is an environment variable you set to give the run-time shared library loader (ld.so) an extra set of directories to look for when searching for shared libraries. Multiple directories can be listed, separated with a colon (:). This list is prepended to the existing list of compiled-in loader paths for a given executable, and any system default loader paths.
So, LD_LIBRARY_PATH is for the ld.so runtime shared library loader, If ld.so has already been loaded, changing LD_LIBRARY_PATH won't do anything.
I found a similar discussion on Perl Monks. I noticed someone found rerunning env seemed to work.
One solution is to modify /etc/ld.so.conf
On CentOS/RHEL 6.4, you could create etc/ld.so.conf.d/oracle with this:
/oracle/sw/product/11.2.0/dbhome_1/lib
Obviously, modify as suits your ORACLE_HOME.
Then run
ldconfig -v
You could put the export commands into the start up script for your unix shell which you should have permission to edit. That way, the environment variables will be set whenever you start a new shell and all scripts and programs that use Oracle will pick them up.
I just went through something similar. I had to make sure that the Oracle environment was setup before anything else called it. Make sure the BEGIN block is before any other "use" statements. In my case, something was being called in Apache's httpd.conf file, so I had to setup my environment there instead of in my package.
Having problems getting CPAN to work with a MiniCPAN repository from within a script (aim is a code deployment system to build local modules together with modules from CPAN, install to a local-lib, and then sync out to servers)
$HOME/.cpan/CPAN/MyConfig.pm exists, with urllist set to ['file:///home/user/minicpan/']
The (non-CPAN) module distribution was injected sucessfully into the minicpan repo, and file exists: e.g. /home/user/minicpan/authors/U/US/USER/My-Module-0.01.tar.gz.
The author is in .../01mailrc.txt.gz, module is in .../modules/02packages.details.txt.gz
The module is found and installs via the cpan shell.
Fails through following code:
CPAN::HandleConfig->load;
CPAN::Shell::setup_output;
CPAN::Index->reload;
# dumping config here shows urllist set correctly,
# and config exactly the same as through shell
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
print Dumper($CPAN::Config);
CPAN::Shell->install("My::Module");
Either doesn't find module ("Cannot install My::Module, don't know what it is.") or claims is up to date (My::Module is up to date (0.01))
Module is not installed in the local-lib (and not anywhere else on machine, e.g. in /usr/...)
Local-lib environment variables are set via
eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/locallib) in bash profile
After getting either error (including 'Module is up to date'), a normal 'install' in the shell works without force, as does perl -MCPAN -e "install My::Module", so I presume it's the config not set correctly, but the CPAN.pm docs are rather hard to follow...
(CPAN.pm is v1.9402)
try :
#!/usr/bin/perl -w
system <cpan install My::Module>
Does anyone have any suggestions for a good approach to finding all the CPAN dependencies that might have arisen in a bespoke development project. As tends to be the case your local development environment rarely matches your live one and as you build more and more projects you tend to build up a local library of installed modules. These then lead to you not necessarily noticing that your latest project has a requirement on a non-core module. As there is generally a requirement to package the entire project up for deployment to another group (in our case our operations team), it is important to know what modules should be included in the package.
Does anyone have any insights into the problem.
Thanks
Peter
I've had this problem myself. Devel::Modlist (as suggested by this answer) takes a dynamic approach. It reports the modules that were actually loaded during a particular run of your script. This catches modules that are loaded by any means, but it may not catch conditional requirements. That is, if you have code like this:
if ($some_condition) { require Some::Module }
and $some_condition happens to be false, Devel::Modlist will not list Some::Module as a requirement.
I decided to use Module::ExtractUse instead. It does a static analysis, which means that it will always catch Some::Module in the above example. On the other hand, it can't do anything about code like:
my $module = "Other::Module";
eval "use $module;";
Of course, you could use both approaches and then combine the two lists.
Anyway, here's the solution I came up with:
#! /usr/bin/perl
#---------------------------------------------------------------------
# Copyright 2008 Christopher J. Madsen <perl at cjmweb.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
# GNU General Public License or the Artistic License for more details.
#
# Recursively collect dependencies of Perl scripts
#---------------------------------------------------------------------
use strict;
use warnings;
use File::Spec ();
use Module::CoreList ();
use Module::ExtractUse ();
my %need;
my $core = $Module::CoreList::version{'5.008'};
# These modules have lots of dependencies. I don't need to see them now.
my %noRecurse = map { $_ => 1 } qw(
Log::Log4perl
XML::Twig
);
foreach my $file (#ARGV) {
findDeps($file);
}
foreach my $module (sort keys %need) {
print " $module\n";
}
#---------------------------------------------------------------------
sub findDeps
{
my ($file) = #_;
my $p = Module::ExtractUse->new;
$p->extract_use($file);
foreach my $module ($p->array) {
next if exists $core->{$module};
next if $module =~ /^5[._\d]+/; # Ignore "use MIN-PERL-VERSION"
next if $module =~ /\$/; # Run-time specified module
if (++$need{$module} == 1 and not $noRecurse{$module}) {
my $path = findModule($module);
if ($path) { findDeps($path) }
else { warn "WARNING: Can't find $module\n" }
} # end if first use of $module
} # end foreach $module used
} # end findDeps
#---------------------------------------------------------------------
sub findModule
{
my ($module) = #_;
$module =~ s!::|\'!/!g;
$module .= '.pm';
foreach my $dir (#INC) {
my $path = File::Spec->catfile($dir, $module);
return $path if -f $path;
}
return;
} # end findModule
You'd run this like:
perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl
It prints a list of all non-core modules necessary to run the scripts listed. (Unless they do fancy tricks with module loading that prevent Module::ExtractUse from seeing them.)
You can use online web-service at deps.cpantesters.org that will provide you many useful dependency data. All modules on CPAN already have the link to the dependency site (on the right side of the module page).
In the past I have used Devel::Modlist which is reasonably good allowing you to go
perl -d:Modlist script.pl
To get a list of the required modules.
I have a Make-based build system for all my C/C++ applications (both PC-based and for various embedded projects), and while I love being able to do a top-level build on a fresh machine and verify all dependencies are in place (I check my toolchains in to revision control :D), I've been frustrated at not doing the same for interpreted languages that currently have no makefile in my build system.
I'm tempted to write a script that:
searches my revision control repository for files with the .pl or .pm extension
runs perl -d:Modlist on them (thanks Vagnerr!)
concatenating it to the list of required modules
and finally comparing it to the list of installed modules.
I'd then execute that script as part of my top-level build, so that anyone building anything will know if they have everything they need to run every perl script they got from revision control. If there is some perl script they never run and don't want to CPAN install what's required to run it, they'd have to remove the unwanted script from their harddrive, so the dependency checker can't find them. I know how to modify a perforce client to leave out certain subdirectories when you do a 'sync', I'll have to figure that out for subversion...
I'd suggest making the dependency checker a single script that searches for pl files, as opposed to an individual makefile to check dependencies for each script, or based on a hard-coded list of script names. If you choose a method that requires user action to have a script checked for dependencies, people will forget to perform that action, since they will be able to run the script even if they don't do the dependency check.
Like I said, I haven't implemented the above yet, but this question has prompted me to try to do so. I'll post back with my experience after I'm done.
The 'obvious' way - painful but moderately effective - is to install a brand new build of base Perl in some out of the way location (you aren't going to use this in production), and then try to install your module using this 'virgin' version of Perl. You will find all the missing dependencies. The first time, this could be painful. After the first time, you'll already have the majority of the dependencies covered, and it will be vastly less painful.
Consider running your own local repository of CPAN modules - so that you won't always have to download the code. Also consider how you clean up the out of date modules.
use Acme::Magic::Pony;
Seriously. It will auto-install Perl modules if they turn up missing. See the Acme::Magic::Pony page in CPAN.
Its a "horse that's bolted" answer but I've got into the habit of creating a Bundle file with all my dependencies. Thus when I go to a new environment I just copy it over and install it.
For eg. I have a Baz.pm
package Bundle::Baz;
$VERSION = '0.1';
1;
__END__
=head1 NAME
Bundle::Baz
=head1 SYNOPSIS
perl -MCPAN -e 'install Bundle::Baz'
=head1 CONTENTS
# Baz's modules
XML::Twig
XML::Writer
Perl6::Say
Moose
Put this in ~/.cpan/Bundle/ (or wherever your .cpan lives) and then install 'Bundle::Baz' like a normal CPAN module. This then installs all the modules listed under "=head1 CONTENTS".
Here is a quickie bash function (using the excellent ack):
# find-perl-module-use <directory> (lib/ by default)
function find-perl-module-use() {
dir=${1:-lib}
ack '^\s*use\s+.*;\s*$' $dir | awk '{ print $2 }' | sed 's/();\?$\|;$//' | sort | uniq
ack '^\s*use\s+base\s+.*;\s*$' $dir | awk '{ print $3 }' | sed 's/();\?$\|;$//' | sort | uniq
}