Cleanup that namespacing mess
Peter Rabbitson [Sat, 19 Mar 2011 11:40:45 +0000 (12:40 +0100)]
24 files changed:
Changes
Makefile.PL
lib/DBIx/Class/Admin/Descriptive.pm
lib/DBIx/Class/Componentised.pm
lib/DBIx/Class/DB.pm
lib/DBIx/Class/InflateColumn.pm
lib/DBIx/Class/InflateColumn/File.pm
lib/DBIx/Class/Optional/Dependencies.pm
lib/DBIx/Class/Relationship/CascadeActions.pm
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSetColumn.pm
lib/DBIx/Class/Row.pm
lib/DBIx/Class/SQLMaker.pm
lib/DBIx/Class/SQLMaker/MSSQL.pm
lib/DBIx/Class/SQLMaker/MySQL.pm
lib/DBIx/Class/SQLMaker/Oracle.pm
lib/DBIx/Class/SQLMaker/OracleJoins.pm
lib/DBIx/Class/SQLMaker/SQLite.pm
lib/DBIx/Class/Serialize/Storable.pm
lib/DBIx/Class/Storage/DBI/Sybase/MSSQL.pm
lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm
lib/DBIx/Class/Storage/Statistics.pm
lib/DBIx/Class/Storage/TxnScopeGuard.pm
t/55namespaces_cleaned.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index db1bbae..b4693a4 100644 (file)
--- a/Changes
+++ b/Changes
@@ -34,6 +34,7 @@ Revision history for DBIx::Class
         - Only load Class::C3 and friends if necessary ($] < 5.010)
         - Greatly reduced loading of non-essential modules to aid startup
           time (mainly benefiting CGI users)
+        - Make sure all namespaces are clean of rogue imports
 
 0.08127 2011-01-19 16:40 (UTC)
     * New Features / Changes
index 71b477f..824a047 100644 (file)
@@ -58,7 +58,7 @@ my $test_requires = {
 my $runtime_requires = {
   'Carp::Clan'               => '6.0',
   'Class::Accessor::Grouped' => '0.10002',
-  'Class::C3::Componentised' => '1.0008',
+  'Class::C3::Componentised' => '1.0009',
   'Class::Inspector'         => '1.24',
   'Config::Any'              => '0.20',
   'Context::Preserve'        => '0.01',
index 45fcb19..9326fca 100644 (file)
@@ -1,10 +1,10 @@
 package     # hide from PAUSE
     DBIx::Class::Admin::Descriptive;
 
-use DBIx::Class::Admin::Usage;
 
 use base 'Getopt::Long::Descriptive';
 
+require DBIx::Class::Admin::Usage;
 sub usage_class { 'DBIx::Class::Admin::Usage'; }
 
 1;
index 57b143b..7e398ca 100644 (file)
@@ -5,9 +5,12 @@ use strict;
 use warnings;
 
 use base 'Class::C3::Componentised';
-use Carp::Clan qw/^DBIx::Class|^Class::C3::Componentised/;
 use mro 'c3';
 
+use Carp::Clan qw/^DBIx::Class|^Class::C3::Componentised/;
+use namespace::clean;
+
+
 my $warned;
 
 # this warns of subtle bugs introduced by UTF8Columns hacky handling of store_column
index 083b83d..c81cda9 100644 (file)
@@ -17,13 +17,9 @@ unless ($INC{"DBIx/Class/CDBICompat.pm"}) {
 
 __PACKAGE__->load_components(qw/ResultSetProxy/);
 
-{
-    no warnings 'once';
-    *dbi_commit = \&txn_commit;
-    *dbi_rollback = \&txn_rollback;
-}
-
 sub storage { shift->schema_instance(@_)->storage; }
+sub dbi_commit { shift->txn_commit(@_) }
+sub dbi_rollback { shift->txn_rollback(@_) }
 
 =head1 NAME
 
index e9de5da..2c6a955 100644 (file)
@@ -2,7 +2,6 @@ package DBIx::Class::InflateColumn;
 
 use strict;
 use warnings;
-use Scalar::Util qw/blessed/;
 
 use base qw/DBIx::Class::Row/;
 
index 951b76e..634bafc 100644 (file)
@@ -6,8 +6,9 @@ use base 'DBIx::Class';
 use File::Path;
 use File::Copy;
 use Path::Class;
-
 use Carp::Clan qw/^DBIx::Class/;
+use namespace::clean;
+
 carp 'InflateColumn::File has entered a deprecation cycle. This component '
     .'has a number of architectural deficiencies that can quickly drive '
     .'your filesystem and database out of sync and is not recommended '
@@ -18,6 +19,8 @@ carp 'InflateColumn::File has entered a deprecation cycle. This component '
     .'DBIC_IC_FILE_NOWARN to a true value to disable  this warning.'
 unless $ENV{DBIC_IC_FILE_NOWARN};
 
+
+
 __PACKAGE__->load_components(qw/InflateColumn/);
 
 sub register_column {
index 6f7c10d..9caf05b 100644 (file)
@@ -3,7 +3,7 @@ package DBIx::Class::Optional::Dependencies;
 use warnings;
 use strict;
 
-use Carp;
+use Carp ();
 
 # NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
 # This module is to be loaded by Makefile.PM on a pristine system
@@ -411,11 +411,11 @@ my $reqs = {
 sub req_list_for {
   my ($class, $group) = @_;
 
-  croak "req_list_for() expects a requirement group name"
+  Carp::croak "req_list_for() expects a requirement group name"
     unless $group;
 
   my $deps = $reqs->{$group}{req}
-    or croak "Requirement group '$group' does not exist";
+    or Carp::croak "Requirement group '$group' does not exist";
 
   return { %$deps };
 }
@@ -425,7 +425,7 @@ our %req_availability_cache;
 sub req_ok_for {
   my ($class, $group) = @_;
 
-  croak "req_ok_for() expects a requirement group name"
+  Carp::croak "req_ok_for() expects a requirement group name"
     unless $group;
 
   return $class->_check_deps($group)->{status};
@@ -434,7 +434,7 @@ sub req_ok_for {
 sub req_missing_for {
   my ($class, $group) = @_;
 
-  croak "req_missing_for() expects a requirement group name"
+  Carp::croak "req_missing_for() expects a requirement group name"
     unless $group;
 
   return $class->_check_deps($group)->{missing};
@@ -443,7 +443,7 @@ sub req_missing_for {
 sub req_errorlist_for {
   my ($class, $group) = @_;
 
-  croak "req_errorlist_for() expects a requirement group name"
+  Carp::croak "req_errorlist_for() expects a requirement group name"
     unless $group;
 
   return $class->_check_deps($group)->{errorlist};
@@ -661,7 +661,7 @@ EOD
     'You may distribute this code under the same terms as Perl itself',
   );
 
-  open (my $fh, '>', $podfn) or croak "Unable to write to $podfn: $!";
+  open (my $fh, '>', $podfn) or Carp::croak "Unable to write to $podfn: $!";
   print $fh join ("\n\n", @chunks);
   close ($fh);
 }
index c46f00c..39155a7 100644 (file)
@@ -4,6 +4,7 @@ package # hide from PAUSE
 use strict;
 use warnings;
 use Carp::Clan qw/^DBIx::Class|^Try::Tiny/;
+use namespace::clean;
 
 our %_pod_inherit_config = 
   (
index 8f894a0..5ded4b7 100644 (file)
@@ -12,15 +12,14 @@ use Try::Tiny;
 # not importing first() as it will clash with our own method
 use List::Util ();
 
-use namespace::clean;
-
-
 BEGIN {
   # De-duplication in _merge_attr() is disabled, but left in for reference
   # (the merger is used for other things that ought not to be de-duped)
   *__HM_DEDUP = sub () { 0 };
 }
 
+use namespace::clean;
+
 use overload
         '0+'     => "count",
         'bool'   => "_bool",
index 0879585..8c2962c 100644 (file)
@@ -5,8 +5,9 @@ use warnings;
 
 use base 'DBIx::Class';
 
-use Carp::Clan qw/^DBIx::Class/;
 use DBIx::Class::Exception;
+use Carp::Clan qw/^DBIx::Class/;
+use namespace::clean;
 
 # not importing first() as it will clash with our own method
 use List::Util ();
index 380f1db..5985209 100644 (file)
@@ -8,7 +8,6 @@ use base qw/DBIx::Class/;
 use DBIx::Class::Exception;
 use Scalar::Util 'blessed';
 use Try::Tiny;
-use namespace::clean;
 
 ###
 ### Internal method
@@ -21,6 +20,8 @@ BEGIN {
       : sub () { 0 };
 }
 
+use namespace::clean;
+
 =head1 NAME
 
 DBIx::Class::Row - Basic row methods
index cb9dcd8..1340165 100644 (file)
@@ -73,6 +73,9 @@ BEGIN {
         }
       };
   }
+
+  # Current SQLA pollutes its namespace - clean for the time being
+  namespace::clean->clean_subroutines(qw/SQL::Abstract carp croak confess/);
 }
 
 # the "oh noes offset/top without limit" constant
index 30b0c96..f64d972 100644 (file)
@@ -2,7 +2,6 @@ package # Hide from PAUSE
   DBIx::Class::SQLMaker::MSSQL;
 
 use base qw( DBIx::Class::SQLMaker );
-use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
 
 #
 # MSSQL does not support ... OVER() ... RNO limits
index ccb1195..4eefc9d 100644 (file)
@@ -3,6 +3,7 @@ package # Hide from PAUSE
 
 use base qw( DBIx::Class::SQLMaker );
 use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
+use namespace::clean;
 
 #
 # MySQL does not understand the standard INSERT INTO $table DEFAULT VALUES
index 5c0f7cd..400fc63 100644 (file)
@@ -6,9 +6,9 @@ use strict;
 
 use base qw( DBIx::Class::SQLMaker );
 use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
+use namespace::clean;
 
 BEGIN {
-  use Carp::Clan qw/^DBIx::Class/;
   use DBIx::Class::Optional::Dependencies;
   croak('The following extra modules are required for Oracle-based Storages ' . DBIx::Class::Optional::Dependencies->req_missing_for ('id_shortener') )
     unless DBIx::Class::Optional::Dependencies->req_ok_for ('id_shortener');
index 3bc8ec9..2d3ae29 100644 (file)
@@ -3,6 +3,7 @@ package # Hide from PAUSE
 
 use base qw( DBIx::Class::SQLMaker::Oracle );
 use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
+use namespace::clean;
 
 sub select {
   my ($self, $table, $fields, $where, $rs_attrs, @rest) = @_;
index 50acef2..acf0337 100644 (file)
@@ -2,7 +2,6 @@ package # Hide from PAUSE
   DBIx::Class::SQLMaker::SQLite;
 
 use base qw( DBIx::Class::SQLMaker );
-use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
 
 #
 # SQLite does not understand SELECT ... FOR UPDATE
index 7d57aea..b7bba43 100644 (file)
@@ -4,6 +4,7 @@ use warnings;
 use Storable;
 
 use Carp::Clan qw/^DBIx::Class/;
+use namespace::clean;
 
 carp 'The Serialize::Storable component is now *DEPRECATED*. It has not '
     .'been providing any useful functionality for quite a while, and in fact '
index 04eda45..c238e98 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use Carp::Clan qw/^DBIx::Class/;
+use namespace::clean;
 
 carp 'Setting of storage_type is redundant as connections through DBD::Sybase'
     .' are now properly recognized and reblessed into the appropriate subclass'
index 71d6e34..0757a4b 100644 (file)
@@ -8,7 +8,9 @@ use base qw/
   DBIx::Class::Storage::DBI::MSSQL
 /;
 use mro 'c3';
+
 use Carp::Clan qw/^DBIx::Class/;
+use namespace::clean;
 
 __PACKAGE__->datetime_parser_type(
   'DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::DateTime::Format'
index d4937d1..714c8fb 100644 (file)
@@ -4,6 +4,7 @@ use warnings;
 
 use base qw/DBIx::Class/;
 use IO::File;
+use namespace::clean;
 
 __PACKAGE__->mk_group_accessors(simple => qw/callback _debugfh silence/);
 
index 843ad91..56c8c81 100644 (file)
@@ -6,7 +6,6 @@ use Carp::Clan qw/^DBIx::Class/;
 use Try::Tiny;
 use Scalar::Util qw/weaken blessed/;
 use DBIx::Class::Exception;
-use namespace::clean;
 
 # temporary until we fix the $@ issue in core
 # we also need a real appendable, stackable exception object
@@ -20,6 +19,8 @@ BEGIN {
   }
 }
 
+use namespace::clean;
+
 my ($guards_count, $compat_handler, $foreign_handler);
 
 sub new {
diff --git a/t/55namespaces_cleaned.t b/t/55namespaces_cleaned.t
new file mode 100644 (file)
index 0000000..faf98b9
--- /dev/null
@@ -0,0 +1,131 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use File::Find;
+use File::Spec;
+use B qw/svref_2object/;
+
+# makes sure we can load at least something
+use DBIx::Class;
+
+my @modules = grep {
+  my $mod = $_;
+
+  # trap deprecation warnings and whatnot
+  local $SIG{__WARN__} = sub {};
+
+  # not all modules are loadable at all times
+  eval "require $mod" ? $mod : do {
+    SKIP: { skip "Failed require of $mod: $@", 1 }A
+    ();
+  };
+
+
+} find_modules();
+
+# have an exception table for old and/or weird code we are not sure
+# we *want* to clean in the first place
+my $skip_idx = { map { $_ => 1 } (
+  (grep { /^DBIx::Class::CDBICompat/ } @modules), # too crufty to touch
+  'SQL::Translator::Producer::DBIx::Class::File', # ditto
+
+  # not sure how to handle type libraries
+  'DBIx::Class::Storage::DBI::Replicated::Types',
+  'DBIx::Class::Admin::Types',
+
+  # G::L::D is unclean, but we never inherit from it
+  'DBIx::Class::Admin::Descriptive',
+  'DBIx::Class::Admin::Usage',
+) };
+
+my $has_cmop = eval { require Class::MOP };
+
+# can't use Class::Inspector for the mundane parts as it does not
+# distinguish imports from anything else, what a crock of...
+# Class::MOP is not always available either - hence just do it ourselves
+
+my $seen; #inheritance means we will see the same method multiple times
+
+for my $mod (@modules) {
+  SKIP: {
+    skip "$mod exempt from namespace checks",1 if $skip_idx->{$mod};
+
+    my %all_method_like = do {
+      no strict 'refs';
+      map {
+        my $m = $_;
+        map
+          { *{"${m}::$_"}{CODE} ? ( $_ => *{"${m}::$_"}{CODE} ) : () }
+          keys %{"${m}::"}
+      } (reverse @{mro::get_linear_isa($mod)});
+    };
+
+    my %parents = map { $_ => 1 } @{mro::get_linear_isa($mod)};
+
+    my %roles;
+    if ($has_cmop and my $mc = Class::MOP::class_of($mod)) {
+      if ($mc->can('calculate_all_roles_with_inheritance')) {
+        $roles{$_->name} = 1 for ($mc->calculate_all_roles_with_inheritance);
+      }
+    }
+
+    for my $name (keys %all_method_like) {
+
+      # overload is a funky thing - it is neither cleaned, and its imports are named funny
+      next if $name =~ /^\(/;
+
+      my $gv = svref_2object($all_method_like{$name})->GV;
+      my $origin = $gv->STASH->NAME;
+
+      next if $seen->{"${origin}:${name}"}++;
+
+      TODO: {
+        local $TODO = 'CAG does not clean its BEGIN constants' if $name =~ /^__CAG_/;
+        is ($gv->NAME, $name, "Properly named $name method at $origin");
+      }
+
+      if ($origin eq $mod) {
+        pass ("$name is a native $mod method");
+      }
+      elsif ($roles{$origin}) {
+        pass ("${mod}::${name} came from consumption of role $origin");
+      }
+      elsif ($parents{$origin}) {
+        pass ("${mod}::${name} came from proper parent-class $origin");
+      }
+      else {
+        my $via;
+        for (reverse @{mro::get_linear_isa($mod)} ) {
+          if ( ($_->can($name)||'') eq $all_method_like{$name} ) {
+            $via = $_;
+            last;
+          }
+        }
+        fail ("${mod}::${name} appears to have entered inheritance chain by import into "
+            . ($via || 'UNKNOWN')
+        );
+      }
+    }
+  }
+}
+
+sub find_modules {
+  my @modules;
+
+  find({
+    wanted => sub {
+      -f $_ or return;
+      s/\.pm$// or return;
+      s/^ (?: lib | blib . (?:lib|arch) ) . //x;
+      push @modules, join ('::', File::Spec->splitdir($_));
+    },
+    no_chdir => 1,
+  }, (-e 'blib' ? 'blib' : 'lib') );
+
+  return sort @modules;
+}
+
+
+done_testing;