| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #========================================================================================= | 
| 2 |  |  |  |  |  |  | package ensure ;          # a pragma | 
| 3 |  |  |  |  |  |  | #========================================================================================= | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 1 |  |  | 1 |  | 21425 | use 5.006 ; use v5.8.8 ;  # Not tested for anything less | 
|  | 1 |  |  | 1 |  | 6 |  | 
|  | 1 |  |  |  |  | 48 |  | 
|  | 1 |  |  |  |  | 12 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 50 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 1 |  |  | 1 |  | 6 | use strict ; | 
|  | 1 |  |  |  |  | 8 |  | 
|  | 1 |  |  |  |  | 60 |  | 
| 8 | 1 |  |  | 1 |  | 6 | use warnings ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 76 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | our $VERSION = '1.10' ;	  # 14-Oct-2008 | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | #========================================================================================= | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 1 |  |  | 1 |  | 5 | use Exporter () ;         # Exporter::import used explicitly | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1112 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our @EXPORT    = qw(import) ; | 
| 17 |  |  |  |  |  |  | our @EXPORT_OK = qw(register) ; | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | #========================================================================================= | 
| 20 |  |  |  |  |  |  | # We work on the basis that in all entries in the symbol table have a defined {SCALAR} | 
| 21 |  |  |  |  |  |  | # part -- whether there is a scalar or not. | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | test_scalar_symbol() or die "*** symbol table form changed -- package 'ensure' broken\n" ; | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | sub test_scalar_symbol { | 
| 26 | 1 |  |  | 1 | 0 | 1 | return defined(*{stash(__PACKAGE__)->{'test_scalar_symbol'}}{SCALAR}) ; | 
|  | 1 |  |  |  |  | 3 |  | 
| 27 |  |  |  |  |  |  | } ; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | #========================================================================================= | 
| 30 |  |  |  |  |  |  | # Tables of packages and variables known to ensure | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | my %packages  = () ;    # Keys   = packages registered for ensure CHECK processing | 
| 33 |  |  |  |  |  |  | # Values = ref:Stash for registered packages | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | my %exporters = () ;    # Keys   = packages which we've seen export stuff | 
| 36 |  |  |  |  |  |  | # Values = true => package includes IMPLICIT tag | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | my %no_ensure = () ;    # Keys   = packages with things declared no_ensure | 
| 39 |  |  |  |  |  |  | # Values = [name, name, ...] | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | my %no_scalar = () ;    # Keys   = address of undefined scalar declared 'no ensure' | 
| 42 |  |  |  |  |  |  | # Values = exporting package | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | my $ensure_errors = 0 ; # Count of errors.  Dies at end of ensure CHECK if != 0. | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | #========================================================================================= | 
| 47 |  |  |  |  |  |  | # Manual registration | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | register(__PACKAGE__) ; # Register ourselves | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | sub register {          # May be used, eg, to register 'main' | 
| 52 | 2 |  |  | 2 | 0 | 3 | my ($p) = @_ ; | 
| 53 | 2 |  | 33 |  |  | 10 | $packages{$p} ||= stash($p) ; | 
| 54 |  |  |  |  |  |  | } ; | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | #========================================================================================= | 
| 57 |  |  |  |  |  |  | # Two small utilities | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub err {               # Issue warning message and increment $ensure_errors | 
| 60 | 0 |  |  | 0 | 0 | 0 | warn '+++ ensure: ', @_, "\n" ; | 
| 61 | 0 |  |  |  |  | 0 | return $ensure_errors++ ; | 
| 62 |  |  |  |  |  |  | } ; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | sub crunch {		# Die | 
| 65 | 0 |  |  | 0 | 0 | 0 | die  '*** ensure: ', @_, "\n" ; | 
| 66 |  |  |  |  |  |  | } ; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | sub suq {               # Sort given list and ensure all entries are unique | 
| 69 | 0 |  |  | 0 | 0 | 0 | my %l = map { ($_, undef) } @_ ; | 
|  | 0 |  |  |  |  | 0 |  | 
| 70 | 0 |  |  |  |  | 0 | return sort keys %l ; | 
| 71 |  |  |  |  |  |  | } ; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | #========================================================================================= | 
| 74 |  |  |  |  |  |  | # ensure::import | 
| 75 |  |  |  |  |  |  | # ============== | 
| 76 |  |  |  |  |  |  | # | 
| 77 |  |  |  |  |  |  | # This will be invoked: | 
| 78 |  |  |  |  |  |  | # | 
| 79 |  |  |  |  |  |  | #   a. when a package does 'use ensure', which: | 
| 80 |  |  |  |  |  |  | # | 
| 81 |  |  |  |  |  |  | #       - registers the package for the ensure CHECK block checks. | 
| 82 |  |  |  |  |  |  | # | 
| 83 |  |  |  |  |  |  | #       - imports into the package the ensure::import function. | 
| 84 |  |  |  |  |  |  | # | 
| 85 |  |  |  |  |  |  | #   b. when a package which has done 'use ensure' is itself used: | 
| 86 |  |  |  |  |  |  | # | 
| 87 |  |  |  |  |  |  | #       - the first time this happens, the package's exports are checked. | 
| 88 |  |  |  |  |  |  | # | 
| 89 |  |  |  |  |  |  | #       - in all cases the import list extensions (:ALL :NONE :IMPLICIT) are | 
| 90 |  |  |  |  |  |  | #         implemented, before jumping to the standard Exporter::import. | 
| 91 |  |  |  |  |  |  | # | 
| 92 |  |  |  |  |  |  | # Requires: $ep      -- package which is being imported from      ) passed to... | 
| 93 |  |  |  |  |  |  | #           @imports -- import list, from "use Fred (@import) ;"  ) ...Exporter::import | 
| 94 |  |  |  |  |  |  | # | 
| 95 |  |  |  |  |  |  | # Returns:  nothing | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | sub import { | 
| 98 | 1 |  |  | 1 |  | 11 | my $ep = $_[0] ; | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | # If we are running the import on behalf of ourselves, we register importing package. | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 1 |  |  |  |  | 2 | my $ip = '' ; | 
| 103 | 1 | 50 |  |  |  | 4 | if ($ep eq __PACKAGE__) { register($ip = scalar(caller)) ; } ; | 
|  | 1 |  |  |  |  | 6 |  | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | # If this is the first time we have seen this package export stuff, we run checks | 
| 106 |  |  |  |  |  |  | # across the export declarations. | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 1 | 50 |  |  |  | 8 | my $implicit = exists($exporters{$ep}) ? $exporters{$ep} : check_exports($ep) ; | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | # Now we deal with the import list, if it is not empty | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 1 | 50 |  |  |  | 5 | if (scalar(@_) > 1) { | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 0 | 0 | 0 |  |  | 0 | if   ($_[1] eq ':ALL') { | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | # Importing ':ALL' -- replace ':ALL' by contents of @EXPORT and @EXPORT_OK | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 0 |  |  |  |  | 0 | my $st = $packages{$ep} ; | 
| 119 | 0 | 0 |  |  |  | 0 | splice( @_, 1, 1, suq(@{stash_value($st, '@EXPORT'   ) || []}, | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 120 | 0 |  |  |  |  | 0 | @{stash_value($st, '@EXPORT_OK') || []}) ) ; | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  | elsif ( ($_[1] eq ':NONE') || (!$implicit && ($_[1] eq ':IMPLICIT')) ) { | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | # Importing ':NONE' or ':IMPLICIT' when no IMPLICIT tag exists. | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 0 |  |  |  |  | 0 | my $i = 2 ; | 
| 127 | 0 |  | 0 |  |  | 0 | while (defined($_[$i]) && ($_[$i] =~ m/^!/)) { $i++ ; } ; | 
|  | 0 |  |  |  |  | 0 |  | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 0 |  |  |  |  | 0 | splice(@_, 1, $i-1) ;     # Drop :NONE/:IMPLICIT and following '!' | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | # Give up now if nothing left of list | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 0 | 0 |  |  |  | 0 | if (scalar(@_) == 1) { return ; } ; # Give up now if nothing left of list | 
|  | 0 |  |  |  |  | 0 |  | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  | elsif ( $implicit && ($_[1] ne ':IMPLICIT') && ($_[1] !~ m/^!/) ) { | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | # Exporting package has 'IMPLICIT' tag and import list a) is not empty, | 
| 138 |  |  |  |  |  |  | #                                                  and b) does not start ':IMPLICIT' | 
| 139 |  |  |  |  |  |  | #                                                  and c) does not start '!...' | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 0 |  |  |  |  | 0 | splice(@_, 1, 0, ':IMPLICIT') ; | 
| 142 |  |  |  |  |  |  | } ; | 
| 143 |  |  |  |  |  |  | } ; | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # Now we can proceed to standard import ! | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 1 | 50 | 33 |  |  | 8 | if (($ip eq 'main') && (scalar(@_) == 1)) | 
| 148 | 1 |  |  |  |  | 12 | { return ; } ;		# (Unless importing self to main, in default fashion.) | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 0 |  |  |  |  | 0 | goto &Exporter::import ;      # As if called in the first place | 
| 151 |  |  |  |  |  |  | } ; | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | #========================================================================================= | 
| 154 |  |  |  |  |  |  | # check_exports: run checks across exports & establish whether has 'IMPLICIT' tag. | 
| 155 |  |  |  |  |  |  | # | 
| 156 |  |  |  |  |  |  | # Checks that: | 
| 157 |  |  |  |  |  |  | # | 
| 158 |  |  |  |  |  |  | #   a) everything in @EXPORT & @EXPORT_OK is defined, except where declared 'no ensure' | 
| 159 |  |  |  |  |  |  | # | 
| 160 |  |  |  |  |  |  | #   b) everything in %EXPORT_TAGS (other than 'IMPLICIT') must appear in @EXPORT or | 
| 161 |  |  |  |  |  |  | #      @EXPORT_OK. | 
| 162 |  |  |  |  |  |  | # | 
| 163 |  |  |  |  |  |  | #   c) everything in any 'IMPLICIT' tag must appear in @EXPORT. | 
| 164 |  |  |  |  |  |  | # | 
| 165 |  |  |  |  |  |  | #   d) everything in @EXPORT_FAIL must appear in @EXPORT or @EXPORT_OK. | 
| 166 |  |  |  |  |  |  | # | 
| 167 |  |  |  |  |  |  | # Sets $exporters{$ep} = true iff there is an 'IMPLICIT' tag, false otherwise. | 
| 168 |  |  |  |  |  |  | # | 
| 169 |  |  |  |  |  |  | # NB: to be called the first time the package is seen exporting stuff. | 
| 170 |  |  |  |  |  |  | # | 
| 171 |  |  |  |  |  |  | # Requires: $ep    -- name of package which is exporting stuff -- default is caller ! | 
| 172 |  |  |  |  |  |  | # | 
| 173 |  |  |  |  |  |  | # Returns:  true => exporting package has an 'IMPLICIT' tag | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | sub check_exports { | 
| 176 | 1 |  |  | 1 | 0 | 2 | my ($ep) = @_ ; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | #---------------------------------------------------------------------------------- | 
| 179 |  |  |  |  |  |  | # Get the stash for the exporting package -- must be registered already !! | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 1 | 50 |  |  |  | 4 | my $st = $packages{$ep} | 
| 182 |  |  |  |  |  |  | or crunch "check_exports: package $ep not registered" ; | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | #---------------------------------------------------------------------------------- | 
| 185 |  |  |  |  |  |  | # a) check contents of @EXPORT & @EXPORT_OK, given any 'no ensure' declarations | 
| 186 |  |  |  |  |  |  | # | 
| 187 |  |  |  |  |  |  | #   Names in @EXPORT & @EXPORT_OK are checked thus: | 
| 188 |  |  |  |  |  |  | # | 
| 189 |  |  |  |  |  |  | #     * name   -- requires: glob{CODE}, SCALAR or REF | 
| 190 |  |  |  |  |  |  | #     * $name  -- requires: glob{SCALAR} to have a defined value | 
| 191 |  |  |  |  |  |  | #     * @name  -- requires: glob{ARRAY} | 
| 192 |  |  |  |  |  |  | #     * %name  -- requires: glob{HASH} | 
| 193 |  |  |  |  |  |  | #     * &name  -- requires: glob{CODE} | 
| 194 |  |  |  |  |  |  | #     * *name  -- requires: the name to exist as glob | 
| 195 |  |  |  |  |  |  | # | 
| 196 |  |  |  |  |  |  | #   Note that the undecorated name works for 5.10.0 and onwards constant values. | 
| 197 |  |  |  |  |  |  | # | 
| 198 |  |  |  |  |  |  | #   Note that for $name this means that it must have some value other than 'undef'. | 
| 199 |  |  |  |  |  |  | #   (This is because it is not possible to distinguish no $name declaration at all | 
| 200 |  |  |  |  |  |  | #   from a declaration which leaves the value undefined.) | 
| 201 |  |  |  |  |  |  | # | 
| 202 |  |  |  |  |  |  | #   Names declared 'no ensure' *must* fail the above. | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 1 |  | 50 |  |  | 3 | my $exp = stash_value($st, '@EXPORT'   ) || [] ; | 
| 205 | 1 |  | 50 |  |  | 3 | my $eok = stash_value($st, '@EXPORT_OK') || [] ; | 
| 206 | 1 |  | 50 |  |  | 6 | my $nen = $no_ensure{$ep} || [] ; | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | # Collect all exports (from EXPORT and EXPORT_OK) & all 'no ensure' names. | 
| 209 |  |  |  |  |  |  |  | 
| 210 | 1 |  |  |  |  | 2 | my %all_exports = map { ($_, 1) } @$exp, @$eok ; | 
|  | 2 |  |  |  |  | 7 |  | 
| 211 | 1 |  |  |  |  | 2 | my %undefined   = map { ($_, 1) } @$nen ; | 
|  | 0 |  |  |  |  | 0 |  | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 1 |  |  |  |  | 8 | foreach my $name (sort keys %all_exports) { | 
| 214 | 2 |  |  |  |  | 5 | my ($id, $t) = undecorate($name) ; | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 2 |  |  |  |  | 7 | my $rv  = $st->{$id} ; | 
| 217 | 2 |  |  |  |  | 4 | my $def = defined($rv) ; | 
| 218 | 2 | 50 |  |  |  | 5 | if ($def) { | 
| 219 | 2 | 50 |  |  |  | 5 | if (!ref($rv)) { | 
| 220 | 2 | 50 |  |  |  | 8 | if    ($t eq 'SCALAR') { $def = defined(${$rv = *$rv{$t}}) ;  } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 221 | 2 |  | 50 |  |  | 13 | elsif ($t ne 'GLOB')   { $def = defined(*$rv{$t || 'CODE'}) ; } ; | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  | else { | 
| 224 | 0 |  | 0 |  |  | 0 | $def = ($t eq '') || ($t eq 'CODE') ; | 
| 225 |  |  |  |  |  |  | } ; | 
| 226 |  |  |  |  |  |  | } ; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 2 | 50 | 33 |  |  | 25 | if (exists($undefined{$name}) || (($t eq 'CODE') && exists($undefined{$id})) | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 229 |  |  |  |  |  |  | || (($t eq '') && exists($undefined{'&'.$id}))) { | 
| 230 | 0 | 0 |  |  |  | 0 | if ($def) { | 
|  |  | 0 |  |  |  |  |  | 
| 231 | 0 |  |  |  |  | 0 | err "'$name' in '$ep\' is declared 'no ensure', but is defined" ; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  | elsif ($t eq 'SCALAR') { | 
| 234 | 1 | 0 |  | 1 |  | 7 | if (!defined($rv)) { no strict 'refs' ; $rv = \${"$ep\:\:$id"} ; } ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1085 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 235 | 0 |  |  |  |  | 0 | $no_scalar{"$rv"} = $ep ; | 
| 236 |  |  |  |  |  |  | } ; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  | else { | 
| 239 | 2 | 50 |  |  |  | 8 | if (!$def) { | 
| 240 | 0 |  |  |  |  | 0 | err "'$name' is exported by '$ep', but is not defined" ; | 
| 241 |  |  |  |  |  |  | } ; | 
| 242 |  |  |  |  |  |  | } ; | 
| 243 |  |  |  |  |  |  | } ; | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | #---------------------------------------------------------------------------------- | 
| 246 |  |  |  |  |  |  | # b) check that everything in the %EXPORT_TAGS is in @EXPORT or @EXPORT_OK | 
| 247 |  |  |  |  |  |  | #    (except for any IMPLICIT tag). | 
| 248 |  |  |  |  |  |  | # c) check that everything in any %EXPORT_TAGS{IMPLICIT} is in @EXPORT | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 1 |  |  |  |  | 3 | my $implicit = 0 ; | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 1 | 50 |  |  |  | 3 | if (my $etg = stash_value($st, '%EXPORT_TAGS')) { | 
| 253 | 0 |  |  |  |  | 0 | foreach my $tag (sort keys %$etg) { | 
| 254 | 0 | 0 |  |  |  | 0 | if ($tag ne 'IMPLICIT') { | 
| 255 | 0 |  |  |  |  | 0 | foreach my $name (suq @{$$etg{$tag}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 256 | 0 | 0 |  |  |  | 0 | if (!exists($all_exports{$name})) { | 
| 257 | 0 |  |  |  |  | 0 | err "'$name' is in '$ep\'s '$tag' tag list,", | 
| 258 |  |  |  |  |  |  | " but not in \@EXPORT or \@EXPORT_OK" ; | 
| 259 |  |  |  |  |  |  | } ; | 
| 260 |  |  |  |  |  |  | } ; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  | else { | 
| 263 | 0 |  |  |  |  | 0 | $implicit = 1 ; | 
| 264 | 0 |  |  |  |  | 0 | my %default = map { ($_, 1) } @$exp ; # That which is in @EXPORT | 
|  | 0 |  |  |  |  | 0 |  | 
| 265 | 0 |  |  |  |  | 0 | foreach my $name (suq @{$$etg{IMPLICIT}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 266 | 0 | 0 |  |  |  | 0 | if (!exists($default{$name})) { | 
| 267 | 0 |  |  |  |  | 0 | err "'$name' is in '$ep\'s 'IMPLICIT' tag list, but not in \@EXPORT" ; | 
| 268 |  |  |  |  |  |  | } ; | 
| 269 |  |  |  |  |  |  | } ; | 
| 270 |  |  |  |  |  |  | } ; | 
| 271 |  |  |  |  |  |  | } ; | 
| 272 |  |  |  |  |  |  | } ; | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | #---------------------------------------------------------------------------------- | 
| 275 |  |  |  |  |  |  | # d) check that everything in the @EXPORT_FAIL is in @EXPORT or @EXPORT_OK | 
| 276 |  |  |  |  |  |  |  | 
| 277 | 1 | 50 |  |  |  | 4 | if (my $ef = stash_value($st, '@EXPORT_FAIL')) { | 
| 278 | 0 |  |  |  |  | 0 | foreach my $name (suq(@$ef)) { | 
| 279 | 0 | 0 |  |  |  | 0 | if (!exists($all_exports{$name})) { | 
| 280 | 0 |  |  |  |  | 0 | err "'$name' is in '$ep\'s \@EXPORT_FAIL, but not in \@EXPORT or \@EXPORT_OK" ; | 
| 281 |  |  |  |  |  |  | } ; | 
| 282 |  |  |  |  |  |  | } ; | 
| 283 |  |  |  |  |  |  | } ; | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | #---------------------------------------------------------------------------------- | 
| 286 |  |  |  |  |  |  | # Done -- record exporting package and whether it has an 'IMPLICIT' tag | 
| 287 |  |  |  |  |  |  |  | 
| 288 | 1 |  |  |  |  | 5 | return $exporters{$ep} = $implicit ; | 
| 289 |  |  |  |  |  |  | } ; | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | #========================================================================================= | 
| 292 |  |  |  |  |  |  | # ensure::unimport | 
| 293 |  |  |  |  |  |  | # ================ | 
| 294 |  |  |  |  |  |  | # | 
| 295 |  |  |  |  |  |  | # unimport: mechanics for no ensure qw(....) ; | 
| 296 |  |  |  |  |  |  | # | 
| 297 |  |  |  |  |  |  | #   no ensure qw(name $name @name %name &name *name) | 
| 298 |  |  |  |  |  |  | # | 
| 299 |  |  |  |  |  |  | # The export checks use the full name, complete with decoration.  So if you want to | 
| 300 |  |  |  |  |  |  | # export an undefined '@name' (for example) you need to be specific. | 
| 301 |  |  |  |  |  |  | # | 
| 302 |  |  |  |  |  |  | # The CHECK block ignores the decoration.  You can say, for example, that you expect | 
| 303 |  |  |  |  |  |  | # '$name' to be undefined, the effect is that it is deemed OK if nothing at all is | 
| 304 |  |  |  |  |  |  | # defined for 'name'. | 
| 305 |  |  |  |  |  |  | # | 
| 306 |  |  |  |  |  |  | # Requires: $self  = ourselves (__PACKAGE__) ! | 
| 307 |  |  |  |  |  |  | #           list of possibly decorated names | 
| 308 |  |  |  |  |  |  | # | 
| 309 |  |  |  |  |  |  | # Returns:  nothing | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | sub unimport { | 
| 312 | 1 |  |  | 1 |  | 3344 | shift(@_) ;           # Discard self | 
| 313 | 1 |  | 50 |  |  | 4 | push @{$no_ensure{scalar(caller)} ||= []}, @_ ; | 
|  | 1 |  |  |  |  | 11 |  | 
| 314 | 1 |  |  |  |  | 581 | return 1 ; | 
| 315 |  |  |  |  |  |  | } ; | 
| 316 |  |  |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | #========================================================================================= | 
| 318 |  |  |  |  |  |  | # Post Compile-Time Checks -- the ensure CHECK block | 
| 319 |  |  |  |  |  |  | # ================================================== | 
| 320 |  |  |  |  |  |  | # | 
| 321 |  |  |  |  |  |  | # For all packages that have been registered, we look for any completely undefined | 
| 322 |  |  |  |  |  |  | # simple names -- which we treat as undefined subroutine errors, unless declared | 
| 323 |  |  |  |  |  |  | # 'no ensure'. | 
| 324 |  |  |  |  |  |  | # | 
| 325 |  |  |  |  |  |  | # By simple we mean names starting '_' or alphabetic, excluding a small number of | 
| 326 |  |  |  |  |  |  | # well known names. | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | CHECK { | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | # These may appear undefined in the stash or are otherwise not worth checking. | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | # a and b appear if sort is used ? | 
| 333 |  |  |  |  |  |  | # MODIFY_xxx_ATTRIBUTES appear and are undefined if a variable is declared ': shared'. | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 1 |  |  | 1 |  | 6 | my %except = map { ($_, 1) } (qw(a b BEGIN UNITCHECK CHECK INIT END | 
|  | 12 |  |  |  |  | 30 |  | 
| 336 |  |  |  |  |  |  | DESTROY AUTOLOAD | 
| 337 |  |  |  |  |  |  | MODIFY_SCALAR_ATTRIBUTES | 
| 338 |  |  |  |  |  |  | MODIFY_ARRAY_ATTRIBUTES | 
| 339 |  |  |  |  |  |  | MODIFY_HASH_ATTRIBUTES)) ; | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | # Run checks across all registered packages | 
| 342 |  |  |  |  |  |  |  | 
| 343 | 1 |  |  |  |  | 13 | foreach my $pkg (sort keys(%packages)) { | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | # Debug introduces a number of undefined things in 'main', which just get in the way | 
| 346 |  |  |  |  |  |  |  | 
| 347 | 2 | 100 | 33 |  |  | 25 | if (($^D || $^P) && ($pkg eq 'main')) { | 
|  |  |  | 66 |  |  |  |  | 
| 348 | 1 |  |  |  |  | 14 | print STDERR "+++ NB: Debug prevents ensure check for '$pkg'\n" ; | 
| 349 | 1 |  |  |  |  | 3 | next ; | 
| 350 |  |  |  |  |  |  | } ; | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | # Collect any 'no ensure' names | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 1 |  |  |  |  | 3 | my %undefined = () ; | 
| 355 | 1 | 50 |  |  |  | 4 | if (exists($no_ensure{$pkg})) { | 
| 356 | 0 |  |  |  |  | 0 | %undefined = map { s/^[\$@%&*]// ; ($_, 1) } @{$no_ensure{$pkg}} ; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 357 |  |  |  |  |  |  | } ; | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | # Check the stash for this package | 
| 360 |  |  |  |  |  |  |  | 
| 361 | 1 |  |  |  |  | 3 | my $stash = $packages{$pkg} ; # Stash for package | 
| 362 |  |  |  |  |  |  |  | 
| 363 | 1 |  |  |  |  | 11 | NAME: foreach my $name (sort keys %$stash) { | 
| 364 | 16 | 100 | 66 |  |  | 181 | if (($name =~ m/^(?:__|_?\W|_?\d)/)         # Ignore names which are not simple... | 
|  |  |  | 66 |  |  |  |  | 
| 365 |  |  |  |  |  |  | || $except{$name}     # ...or which are exceptional | 
| 366 |  |  |  |  |  |  | || $undefined{$name}) # ...or which are declared 'no ensure' | 
| 367 | 2 |  |  |  |  | 5 | { next NAME ; } ; | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 14 |  |  |  |  | 32 | my $rv = $stash->{$name} ;  # Get the stash entry | 
| 370 |  |  |  |  |  |  |  | 
| 371 | 14 | 50 |  |  |  | 27 | next if !defined($rv);      # Ignore undefined stash entries | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | # OK if stash entry is ref() (=> is 5.10.0 or later 'constant') | 
| 374 |  |  |  |  |  |  | #    or if have a {CODE} value -- these are the commonest cases ! | 
| 375 |  |  |  |  |  |  |  | 
| 376 | 14 | 100 | 66 |  |  | 56 | if (ref($rv) || defined(*$rv{CODE})) { next NAME ; } ; | 
|  | 11 |  |  |  |  | 30 |  | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | # OK if glob has a defined {SCALAR} value | 
| 379 |  |  |  |  |  |  | #          or if undefined {SCALAR} is import of an exported 'no ensure' | 
| 380 |  |  |  |  |  |  |  | 
| 381 | 3 |  |  |  |  | 7 | my $rs = *$rv{SCALAR} ; | 
| 382 | 3 | 100 | 66 |  |  | 19 | if (defined($rs) && (defined($$rs) || exists($no_scalar{"$rs"}))) { next NAME ; } ; | 
|  | 1 |  | 33 |  |  | 3 |  | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  | # OK if glob has at least one of these other types of value. | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 2 |  |  |  |  | 3 | foreach my $type (qw(ARRAY HASH IO FORMAT)) { | 
| 387 | 2 | 50 |  |  |  | 23 | if (defined(*$rv{$type})) { next NAME ; } ; | 
|  | 2 |  |  |  |  | 6 |  | 
| 388 |  |  |  |  |  |  | } ; | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # Generate error for name with no defined value | 
| 391 |  |  |  |  |  |  |  | 
| 392 | 0 |  |  |  |  | 0 | err "$pkg\:\:$name is undefined" ; | 
| 393 |  |  |  |  |  |  | } ; | 
| 394 |  |  |  |  |  |  | } ; | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | # Now...  if any errors seen by ensure, give up ! | 
| 397 |  |  |  |  |  |  |  | 
| 398 | 1 | 50 |  |  |  | 943 | if ($ensure_errors) { crunch "$ensure_errors errors found" ; } ; | 
|  | 0 |  |  |  |  | 0 |  | 
| 399 |  |  |  |  |  |  | } ; | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | #========================================================================================= | 
| 402 |  |  |  |  |  |  | # Stash Access | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | #----------------------------------------------------------------------------------------- | 
| 405 |  |  |  |  |  |  | # stash: get ref:Stash for given package | 
| 406 |  |  |  |  |  |  | # | 
| 407 |  |  |  |  |  |  | # Requires: $pkg   -- package name -- no trailing '::'  -- ASSUMED VALID | 
| 408 |  |  |  |  |  |  | # | 
| 409 |  |  |  |  |  |  | # Returns:  ref:Stash -- i.e. hash containing symbols for given package | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | sub stash { | 
| 412 | 3 |  |  | 3 | 0 | 4 | my ($pkg) = @_ ; | 
| 413 | 1 |  |  | 1 |  | 6 | no strict qw(refs) ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 334 |  | 
| 414 | 3 | 0 |  |  |  | 3 | return *{$pkg.'::'}{HASH}   or crunch "cannot find package '$pkg'" ; | 
|  | 3 |  |  |  |  | 23 |  | 
| 415 |  |  |  |  |  |  | } ; | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | #----------------------------------------------------------------------------------------- | 
| 418 |  |  |  |  |  |  | # stash_value: get value of SCALAR, ARRAY or HASH from given package/stash | 
| 419 |  |  |  |  |  |  | # | 
| 420 |  |  |  |  |  |  | # Requires: $st       -- ref:Stash (as returned by stash()) | 
| 421 |  |  |  |  |  |  | #           $name     -- decorated name of value | 
| 422 |  |  |  |  |  |  | # | 
| 423 |  |  |  |  |  |  | # Returns:  value     -- if SCALAR and scalar is defined | 
| 424 |  |  |  |  |  |  | #           ref:Value -- if ARRAY, HASH and value is defined | 
| 425 |  |  |  |  |  |  | #           undef     -- name not found or value not defined | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | sub stash_value { | 
| 428 | 4 |  |  | 4 | 0 | 6 | my ($st, $name) = @_ ; | 
| 429 |  |  |  |  |  |  |  | 
| 430 | 4 |  |  |  |  | 8 | my ($id, $type) = undecorate($name) ; | 
| 431 | 4 |  |  |  |  | 9 | my $rv = $st->{$id} ; | 
| 432 | 4 | 100 |  |  |  | 10 | if (defined($rv)) { | 
| 433 | 2 | 50 |  |  |  | 4 | if (!ref($rv)) { | 
| 434 | 2 |  |  |  |  | 4 | $rv = *$rv{$type} ; | 
| 435 | 2 | 50 | 33 |  |  | 15 | if (defined($rv) && ($type eq 'SCALAR')) { $rv = $$rv ; } ; | 
|  | 0 |  |  |  |  | 0 |  | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  | else { | 
| 438 | 0 |  |  |  |  | 0 | $rv = undef ;     # ref:SCALAR or ref:REF => 5.10.0 type constant | 
| 439 |  |  |  |  |  |  | } ; | 
| 440 |  |  |  |  |  |  | } ; | 
| 441 |  |  |  |  |  |  |  | 
| 442 | 4 |  |  |  |  | 16 | return $rv ; | 
| 443 |  |  |  |  |  |  | } ; | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | #----------------------------------------------------------------------------------------- | 
| 446 |  |  |  |  |  |  | # undecorate: remove decoration from name and return explicit type, if any | 
| 447 |  |  |  |  |  |  | # | 
| 448 |  |  |  |  |  |  | # Requires: $name     -- possibly decorated name | 
| 449 |  |  |  |  |  |  | # | 
| 450 |  |  |  |  |  |  | # Returns:  ($id, $type)  -- $id    = name less any decoration | 
| 451 |  |  |  |  |  |  | #                            $type  = if decorated: SCALAR, ARRAY, HASH, CODE or GLOB | 
| 452 |  |  |  |  |  |  | #                                        otherwise: '' | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | my %TYPE = qw($ SCALAR  @ ARRAY  % HASH  & CODE  * GLOB) ; | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | sub undecorate { | 
| 457 | 6 |  |  | 6 | 0 | 9 | my ($id) = @_ ; | 
| 458 | 6 |  |  |  |  | 8 | my $type = '' ; | 
| 459 | 6 | 100 |  |  |  | 25 | if ($id =~ s/^([\$@%&*])//) { $type = $TYPE{$1} ; } ; | 
|  | 4 |  |  |  |  | 10 |  | 
| 460 | 6 |  |  |  |  | 16 | return ($id, $type) ; | 
| 461 |  |  |  |  |  |  | } ; | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | #_________________________________________________________________________________________ | 
| 464 |  |  |  |  |  |  | 1 ; # OK -- end of ensure | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | __END__ |