File Coverage

blib/lib/Module/Reload/Selective.pm
Criterion Covered Total %
statement 19 98 19.3
branch 0 20 0.0
condition 12 47 25.5
subroutine 5 7 71.4
pod 0 2 0.0
total 36 174 20.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             ## Emacs: -*- tab-width: 4; -*-
3              
4 1     1   7687 use strict;
  1         3  
  1         68  
5              
6             package Module::Reload::Selective;
7              
8 1     1   5 use vars qw($VERSION); $VERSION = '1.02';
  1         1  
  1         174  
9              
10             =pod
11              
12             =head1 NAME
13              
14             Module::Reload::Selective - Reload perl modules during development
15              
16             =head1 SYNOPSIS
17              
18             Instead of:
19              
20             use Foobar::MyModule;
21              
22             Do this:
23              
24             use Module::Reload::Selective;
25             &Module::Reload::Selective->reload(qw(Foobar::MyModule));
26              
27             Or, if you need the "import" semantics of "use", do this:
28              
29             use Foobar::MyModule (@ImportArgs);
30              
31             Do this:
32              
33             use Module::Reload::Selective;
34             Module::Reload::Selective->reload(qw(Foobar::MyModule));
35             import Foobar::MyModule (@ImportArgs);
36              
37              
38             ... then configure your server or other runtime environment settings
39             to trigger Module::Reload::Selective to only kick in when you need.
40              
41             For example: you could have it kick in only when the web server is
42             running on a particular port number or particular (development) host.
43              
44             =head1 OVERVIEW
45              
46             Utility for module developers to selectively reload needed modules
47             and/or conditionally augment @INC with additional, per-developer
48             library directories, at development time based on environment
49             variables.
50              
51             Particularly helpful in conjunction with mod_perl applications where
52             some or all application logic resides in separate Perl modules that
53             would otherwise not get reloaded until the server restarts.
54              
55             Copyright (c) 2002, Chris Thorman.
56              
57             Released to the public under the terms of the Perl Artistic License.
58              
59             =head1 DETAILS
60              
61             This module defines a "reload" routine that scripts, CGI scripts,
62             Embperl scripts, handlers, etc. can use to reload (re-require) a
63             module or modules, optionally forcing the modules AND ANY MODULES THEY
64             USE, recursively, to reload, even if already previously loaded and
65             listed in %INC.
66              
67             The reloading feature is helpful for when you're actively writing and
68             debugging modules intended to be used with Apache and mod_perl (either
69             used by Apache::Registry or HTML::Embperl script, or handlers, or
70             other mechanisms) and want to ensure that your code changes get
71             reloaded on every hit, even if the module had previously been loaded
72             into the parent or child process.
73              
74             In addition to the selective reloading feature, this module can also
75             (optionally) dynamically prepend some additional paths to @INC to
76             allow programmers to work on, test, and debug private development
77             copies of modules in a private directory while other modules are
78             loaded from a more stable, shared, or public, library directory.
79              
80             The @INC-modifying feature is helpful even if you're only developing
81             command-line perl scripts in an environment where there are multiple
82             programmers and an individual programmer, for testing purposes, needs
83             to optionally load some modules under development from his or her own
84             private source directory in preference to the "standard" locations.
85              
86             This is a common need when multiple Perl developers are working on the
87             same Unix host.
88              
89             How this module differs from Module::Reload:
90              
91             =over 4
92              
93             =item *
94              
95             Module::Reload reloads just files that it sees have changed on disk
96             since the last reload, whereas this module conditionally reloads based
97             on other conditions at runtime; this module also has other features of
98             convenience to develoepers.
99              
100             =back
101              
102             How this module differs from Apache::StatINC:
103              
104             =over 4
105              
106             =item *
107              
108             Reloads requested modules (recursively) regardless of modification
109             date.
110              
111             =item *
112              
113             Skips reloading any modules that have been previously loaded from
114             lib/perl* (or other customizable list of dir name patterns), so you
115             can only reload items outside the standard library locations, by
116             default.
117              
118             =item *
119              
120             Allows dynamic overriding of @INC on a per-USER basis.
121              
122             =item *
123              
124             This module lacks StatINC's ability to disable symbol-redef warnings,
125             so best not to reload modules with const subroutines... (sorry).
126              
127             =item *
128              
129             Works outside of Apache as well as within it (not sure whether this is
130             true of Apache::StatINC), so is testable from the command line, and
131             even useful in a batch script context, if not for its reloading
132             capabilities, then at least for its ability to override the search
133             path on a per-USER basis, allowing the development and debugging of a
134             private copy of a system-wide module or modules.
135              
136             =item *
137              
138             Works fine from within individual pages or scripts; does not
139             necessarily need to be loaded at server startup time.
140              
141             =item *
142              
143             Is a no-op (does not reload) unless certain environment variables
144             and/or options are set, allowing you to leave calls to it in
145             production code with negligible performance hit on non-debugging
146             servers.
147              
148             =back
149              
150             =head1 DISCUSSION
151              
152             To request that a module Foobar::MyModule, and any modules it calls,
153             be reloaded, do this:
154              
155             use Module::Reload::Selective;
156             Module::Reload::Selective->reload(qw(Foobar::MyModule));
157              
158              
159             This reloads the module, executing its BEGIN blocks, syntax-checking
160             it, and recompiling any subroutines it has.
161              
162             Then, if you want to import any semantics from the module into the
163             current namespace, you should directly "import" the module.
164              
165             import Foobar::MyModule (@ImportArgs);
166              
167             IMPORTANT: Under normal circumstances, reload will load the module
168             normally with no difference from the usual behavior of "use"
169             ... i.e. files won't be reloaded if they already have been, and no
170             special modifications to @INC will be applied.
171              
172             BUT, if certain environment variables (see below) are set to non-false
173             values, Module::Reload::Selective will force them and any modules THEY need, to
174             be reloaded from their source file every time, also using temporary
175             modifications to @INC.
176              
177             The variables are:
178              
179             $ENV{RLD} ## Useful for command-line testing/debugging
180              
181             prompt> RLD=1 perl index.cgi
182              
183             Just set this environment variable before invoking the script and the
184             Reloader will be activated.
185              
186             $ENV{DEBUGGING_SERVER} ## Set this in the server startup
187              
188             At server startup, set the environment variable conditionally, only if
189             you're starting up a private debugging server, say, on a different
190             port. You could use something like this in a section in your
191             httpd.conf, for example:
192              
193             if (($My::HostName =~ /^dev/) && $Port == 8081)
194             {
195             $User = 'upload';
196             $Group = 'upload';
197             print STDERR "Starting as user $User/$Group\n" if -t STDERR;
198              
199             push @PerlSetEnv, ['DEBUGGING_SERVER', 1];
200              
201             ## Could also set other Module::Reload::Selective runtime options here.
202             }
203              
204              
205              
206             =head1 RUNTIME OPTIONS
207              
208             Runtime options are initialized by Module::Reload::Selective when it
209             is first "use"d, and may be overridden individually later before
210             calling "reload", by setting a few elements of the
211             $Module::Reload::Selective::Options hash, like this:
212              
213             $Module::Reload::Selective::Options->{SearchProgramDir} = 0;
214              
215              
216             The available options, and their initial default values, are:
217              
218             ReloadOnlyIfEnvVarsSet => 1,
219              
220             ## If 0, always reloads, regardless of environment var settings
221             ## described above.
222              
223             SearchProgramDir => 1,
224              
225             ## If 1, cur working dir of script, as determined from $0, will be
226             ## added to the search paths before reloading.
227              
228             ## This is very handy for keeping private local copies of modules
229             ## being tested in the same directory tree as the application that
230             ## uses them.
231              
232             SearchUserDir => 1,
233              
234             ## If 1, "user dir" as determined by the other "User" options
235             ## below, will added to the search paths, after ProgramDir.
236              
237             DontReloadIfPathContains => ['lib/perl'],
238              
239             ## List of strings that, if found in the loaded path of an already
240             ## loaded module, prevent that module from being re-loaded. By
241             ## specifying "lib/perl" (on Unix), no library modules installed
242             ## in the standard perl library locations will ever be reloaded.
243             ## Force reloading of those, too, by removing that entry, or add
244             ## additional strings to disable additional subdirectories,
245             ## perhaps ones of your own.
246              
247             FirstAdditionalPaths => [],
248             LastAdditionalPaths => [],
249              
250             ## Lists; if non-empty, these specify additional paths to be
251             ## searched before or after any of the obove options, but in any
252             ## case always before any of the other locations normally in @INC.
253              
254             User => '',
255              
256             ## Name of user whose directory will be searched.
257              
258             DefaultUser => $ENV{RELOAD_USER} || $ENV{USER} || $ENV{REMOTE_USER},
259              
260             ## Name of user whose directory will be searched if no User option
261             ## is specified to override it. If empty, no user name will be
262             ## used.
263              
264             UserDirTemplate => '/home/USER/src/lib',
265              
266             ## Path to search when looking for source modules in a User's
267             ## programming directory. If "USER" is in the path, it will be
268             ## substituted at runtime with the value of User or DefaultUser as
269             ## appropriate. The resulting directory path is only added to the
270             ## search paths if it actually exists.
271              
272             =head1 DEBUGGING & ANALYSIS OF WHAT GOT LOADED
273              
274             For debugging purposes, Module::Reload::Selective creates these hash
275             references, in the same format as %INC, that show what the last
276             "reload" command did. You can examine these (e.g. with Data::Dumper)
277             after calling reload if you want to be sure that reload did its job.
278              
279             $Module::Reload::Selective::Debug->{INCHashBefore}
280             $Module::Reload::Selective::Debug->{INCHashAfter}
281              
282             $Module::Reload::Selective::Debug->{NewlyLoaded}
283             $Module::Reload::Selective::Debug->{Reloaded}
284             $Module::Reload::Selective::Debug->{NotReloaded}
285              
286             $Module::Reload::Selective::Debug->{GotLoaded}
287              
288             NewlyLoaded -- modules that weren't loaded (from anywhere) prior to
289             calling reload.
290              
291             Reloaded -- modules that previously appeared in %INC but got reloaded.
292              
293             NotReloaded -- modules that previously appeared in %INC but were not
294             reloaded.
295              
296             GotLoaded -- The union of Reloaded and NewlyLoaded -- i.e. anything
297             that got loaded as a result of the "reload" command.
298              
299             You can examine these by putting something like one of these
300             statements in your code:
301              
302             use Data::Dumper;
303             print &Dumper($Module::Reload::Selective::Debug);
304             print &Dumper($Module::Reload::Selective::Debug->{GotLoaded});
305              
306             For example, if you use HTML::Embperl, you could put the following
307             line in your application:
308              
309            
[+ &Dumper($Module::Reload::Selective::Debug); +]
310              
311             ... and comment it out when done:
312              
313             [#
[+ &Dumper($Module::Reload::Selective::Debug); +]
#]
314              
315             Note: if you use "reload" to force a reload of all your modules into a
316             virgin child process, the "NewlyLoaded" hash should be empty in a web
317             server environment where the Web server has been properly configured
318             to pre-load all necessary modules at server startup. You could use
319             this side-effect as a way to test your server configuration to see if
320             you've remembered to preload everything needed by your application at
321             server startup; anything that shows up in NewlyLoaded is something
322             you've forgotten to preload and you can fix that.
323              
324             To see what private version of @INC was used by "reload", have a look
325             at this debugging variable:
326              
327             $Module::Reload::Selective::Debug->{INCArrayAfterModification}
328              
329             To see what time the last reload occurred, view this variable:
330              
331             $Module::Reload::Selective::Debug->{LastLoadTime}
332              
333             (This, along with the GotLoaded hash, will also help you reassure
334             yourself that the things you wanted to reload really did get reloaded;
335             if GotLoaded doesn't list your module, and/or LastLoadTime did not
336             change, then something did not reload.)
337              
338             =head1 WARNINGS
339              
340             RELOADING IS RECURSIVE
341              
342             If you reload module A that uses module B, module B will be reloaded,
343             too. This allows you to reload all related modules at one time. But
344             if you're not working on A, only on B, it is more efficient to just
345             reload module B. Don't reload more than you need, in other words.
346              
347              
348             RELOADING CAN MESS WITH GLOBALS IN APACHE CHILD PROCESSES
349              
350             Note that the reloaded modules are loaded into the (child) process's
351             global namespace and so will affect all applications served by the
352             affected process... including any bugs you've introduced or modules
353             that failed to compile.
354              
355             So if using Module::Reload::Selective for Web application development, each
356             programmer should be testing with his/her own private Apache server,
357             (possibly running on a unique port).
358              
359             This way when you force the reloading of a buggy version of a module,
360             everyone else's runtime environment is not also screwed up.
361              
362              
363             WARNING: SYMBOL REDEFINITION WARNINGS
364              
365             If the loaded module, or any module it reloads uses constant
366             subroutines, as in constant.pm, you will get warnings every time it
367             reloads. I tried to emulate a trick used by Doug MacEachern in
368             Apache::StatINC to prevent this from happening, but in this version, I
369             haven't been able to get that to work. Suggestions / fixes welcome.
370              
371             =head1 THANKS
372              
373             Thanks to Joshua Pritikin for suggestions and the use of the
374             Module::Reload namespace.
375              
376             =head1 INSTALLATION
377              
378             Using CPAN module:
379              
380             perl -MCPAN -e 'install Module::Reload::Selective'
381              
382             Or manually:
383              
384             tar xzvf Module-Reload-Sel*gz
385             cd Module-Reload-Sel*-?.??
386             perl Makefile.PL
387             make
388             make test
389             make install
390              
391             =head1 SEE ALSO
392              
393             The Module::Reload::Selective home page:
394              
395             http://christhorman.com/projects/perl/Module-Reload-Selective/
396              
397             Apache(3), mod_perl, http://perl.apache.org/src/contrib,
398             Module::Reload, Apache::StatINC.
399              
400             The implementation in Selective.pm.
401              
402             The perlmod manual page.
403              
404             =head1 AUTHOR
405              
406             Chris Thorman
407              
408             Copyright (c) 1995-2002 Chris Thorman. All rights reserved.
409              
410             This program is free software; you can redistribute it and/or modify
411             it under the same terms as Perl itself.
412              
413             =cut
414              
415             {}; ## Get emacs to indent correctly. Sigh.
416              
417 1     1   1213 use Data::Dumper;
  1         14830  
  1         222  
418              
419             BEGIN
420             {
421 1   50 1   10 $Module::Reload::Selective::Debug ||= {};
422              
423 1   50     7 $Module::Reload::Selective::Options ||= {};
424              
425 1   50     7 $Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet} ||= 1;
426 1   50     16 $Module::Reload::Selective::Options->{SearchProgramDir} ||= 1;
427 1   50     6 $Module::Reload::Selective::Options->{SearchUserDir} ||= 1;
428              
429 1   50     7 $Module::Reload::Selective::Options->{DontReloadIfPathContains} ||= ['lib/perl'];
430              
431 1   50     7 $Module::Reload::Selective::Options->{FirstAdditionalPaths} ||= [];
432 1   50     64 $Module::Reload::Selective::Options->{LastAdditionalPaths} ||= [];
433              
434 1   50     1603 $Module::Reload::Selective::Options->{User} ||= '',
      33        
      33        
      50        
435             $Module::Reload::Selective::Options->{DefaultUser} ||= $ENV{RELOAD_USER} || $ENV{USER} || $ENV{REMOTE_USER},
436             $Module::Reload::Selective::Options->{UserDirTemplate} ||= '/home/USER/src/lib',
437              
438             }
439              
440             sub import
441             {
442 1     1   1963 my ($Class, @Args) = @_;
443             }
444              
445              
446             ### reload
447              
448             ### Can be called either procedurally or as a class method. Knows to
449             ### not reload the Module::Reload::Selective class itself.
450              
451             sub reload
452             {
453 0     0 0   my (@PackageNames) = @_;
454              
455 0           my $ReturnVal = undef;
456              
457              
458             ## This module doesn't reload itself. Sorry. Restart
459             ## your server for that.
460              
461 0           @PackageNames = (grep {$_ ne __PACKAGE__} @PackageNames);
  0            
462              
463             ## Do nothing unless given at least one package name to reload.
464              
465 0 0         goto done unless @PackageNames;
466              
467             ## Initialize/empty out the debugging info
468              
469 0           $Module::Reload::Selective::Debug = {};
470              
471             ## RELOAD MODE... kicks in if either of the two environment
472             ## variables is set or the ReloadOnlyIfEnvVarsSet option is turned
473             ## off.
474              
475 0 0 0       if (
      0        
476             $ENV{DEBUGGING_SERVER} ||
477             $ENV{RLD} ||
478             !$Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet}
479             )
480             {
481              
482             ## FIRST MODIFY @INC TO HAVE SOME ADDITIONAL SEARCH DIRS
483             ## PREPENDED...
484              
485 0           my $ExtraSearchDirs = [];
486              
487 0 0 0       if ($Module::Reload::Selective::Options->{FirstAdditionalPaths} &&
  0            
488             @{$Module::Reload::Selective::Options->{FirstAdditionalPaths}})
489             {
490 0           push @$ExtraSearchDirs, @{$Module::Reload::Selective::Options->{FirstAdditionalPaths}};
  0            
491             }
492              
493 0 0         if ($Module::Reload::Selective::Options->{SearchProgramDir})
494             {
495 0           (my $ProgramDir = $0) =~ s|(.*/).*|$1|;
496 0 0         push @$ExtraSearchDirs, $ProgramDir if -d $ProgramDir;
497             }
498              
499 0 0         if ($Module::Reload::Selective::Options->{SearchUserDir})
500             {
501             my $User = ($Module::Reload::Selective::Options->{User } ||
502 0   0       $Module::Reload::Selective::Options->{DefaultUser});
503              
504 0           my $UsersProgrammingDir = $Module::Reload::Selective::Options->{UserDirTemplate};
505 0           $UsersProgrammingDir =~ s/\bUSER\b/$User/g;
506              
507 0 0 0       push @$ExtraSearchDirs, $UsersProgrammingDir if $User && -d $UsersProgrammingDir;
508             }
509            
510 0 0 0       if ($Module::Reload::Selective::Options->{LastAdditionalPaths} &&
  0            
511             @{$Module::Reload::Selective::Options->{LastAdditionalPaths}})
512             {
513 0           push @$ExtraSearchDirs, @{$Module::Reload::Selective::Options->{LastAdditionalPaths}};
  0            
514             }
515            
516             ## Prepend the ExtraSearchDirs to a local copy of @INC so they
517             ## will get searched in order before any of the places in
518             ## @INC.
519              
520 0           local @INC = @INC;
521 0           unshift @INC, @$ExtraSearchDirs;
522            
523 0           $Module::Reload::Selective::Debug->{INCArrayAfterModification} = [@INC];
524              
525             ## die &Dumper(\@INC, $ExtraSearchDirs, $Module::Reload::Selective::Options);
526              
527             ## THEN MODIFY %INC TO REMOVE ANY MENTION OF ITEMS THAT MIGHT
528             ## NEED TO GET RELOADED....
529            
530             ## Before mucking with %INC, get a list of any installed perl
531             ## library modules that we don't want to muck with (any items
532             ## with "lib/perl" in the path).... or any other of a list of
533             ## path elements that should be disabled...
534            
535 0           my $DisabledPatterns = $Module::Reload::Selective::Options->{DontReloadIfPathContains};
536              
537 0           my $DisabledItems = {};
538 0           foreach my $Pattern (@$DisabledPatterns)
539             {
540 0           @$DisabledItems{grep {$INC{$_} =~ m|\Q$Pattern\E|} keys %INC} = undef;
  0            
541             }
542 0           @$DisabledItems{keys %$DisabledItems} = @INC{keys %$DisabledItems};
543            
544             ## die &Dumper($DisabledItems);
545            
546             ## Empty out our private copy of %INC, so "require" doesn't
547             ## think any modules have yet been loaded.
548            
549 0           $Module::Reload::Selective::Debug->{INCHashBefore} = {%INC};
550 0           local %INC = ();
551            
552             ## Restore the disabled items in %INC so we don't reload those.
553            
554 0           @INC{keys %$DisabledItems} = values %$DisabledItems;
555             ## die &Dumper(\%INC);
556            
557              
558             ## THEN LOAD EACH OF THE REQUESTED MODULES...
559              
560 0           foreach my $PackageName (@PackageNames)
561             {
562              
563 0           (my $PackageRelPath = "$PackageName.pm") =~ s|::|/|g;
564            
565             ## Many thanks to Doug MacEachern / Apache::StatINC for
566             ## this attempt turning of warnings for const subroutine
567             ## redefinitions, but I can't seem to get it to work, so it's commented out.
568              
569             ## require Apache::Symbol;
570             ## my $Class = Apache::Symbol::file2class($PackageRelPath);
571             ## $Class->Apache::Symbol::undef_functions( undef, 1 );
572            
573 0           require ($PackageRelPath);
574 0           $ReturnVal = import $PackageName;
575             }
576            
577             ## TAKE A SNAPSHOT OF THE NEW %INC FOR LATER ANALYSIS...
578              
579 0           $Module::Reload::Selective::Debug->{INCHashAfter} = {%INC};
580 0           delete @{$Module::Reload::Selective::Debug->{INCHashAfter}}{keys %$DisabledItems};
  0            
581 0           $Module::Reload::Selective::Debug->{LastLoadTime} = localtime().'';
582              
583             ## %INC and @INC WILL BE RESTORED HERE BY local %INC and local
584             ## @INC GOING OUT OF SCOPE...
585             }
586              
587             ## REGULAR MODE: Do the equivlaent of a "use", except that
588             ## semantics won't be imported into the caller's namespace.
589              
590             else
591             {
592 0           foreach my $PackageName (@PackageNames)
593             {
594 0           (my $PackageRelPath = "$PackageName.pm") =~ s|::|/|g;
595 0           require ($PackageRelPath);
596 0           $ReturnVal = import $PackageName;
597             }
598            
599 0           $Module::Reload::Selective::Debug->{Reload_Disabled_Because} = "No environment variables were set.";
600             }
601            
602             done:
603              
604             ## if %INC was messed with, we analyze the differences between the
605             ## before and after and set some derived hashes.
606              
607 0 0 0       if ($Module::Reload::Selective::Debug->{INCHashBefore} &&
608             $Module::Reload::Selective::Debug->{INCHashAfter})
609             {
610 0           ($Module::Reload::Selective::Debug->{NotReloaded},
611             $Module::Reload::Selective::Debug->{NewlyLoaded},
612             $Module::Reload::Selective::Debug->{Reloaded}) =
613             CompareHashKeys($Module::Reload::Selective::Debug->{INCHashBefore},
614             $Module::Reload::Selective::Debug->{INCHashAfter});
615            
616             ## CompareHashKeys leaves the values undefined; for
617             ## convenience, we pick up the values from the Before and
618             ## After hashes.
619            
620 0           foreach ($Module::Reload::Selective::Debug->{NotReloaded},
621             $Module::Reload::Selective::Debug->{NewlyLoaded},
622             $Module::Reload::Selective::Debug->{Reloaded})
623             {
624 0 0         @{$_}{keys %$_} = (map {($Module::Reload::Selective::Debug->{INCHashAfter }->{$_} ||
  0            
  0            
625             $Module::Reload::Selective::Debug->{INCHashBefore}->{$_})} keys %$_);
626             }
627              
628             ## Finally make another debugging hash of anything that got
629             ## loaded for any reason, whether newly, or re-loaded.
630            
631 0           $Module::Reload::Selective::Debug->{GotLoaded} = {};
632 0           @{$Module::Reload::Selective::Debug->{GotLoaded}}{keys %{$Module::Reload::Selective::Debug->{NewlyLoaded}}} = values %{$Module::Reload::Selective::Debug->{NewlyLoaded}};
  0            
  0            
  0            
633 0           @{$Module::Reload::Selective::Debug->{GotLoaded}}{keys %{$Module::Reload::Selective::Debug->{Reloaded }}} = values %{$Module::Reload::Selective::Debug->{Reloaded }};
  0            
  0            
  0            
634            
635             ## Copy entries for the items that changed into the non-local %INC hash.
636 0           @INC{keys %{$Module::Reload::Selective::Debug->{GotLoaded}}} = values %{$Module::Reload::Selective::Debug->{GotLoaded}};
  0            
  0            
637            
638             }
639            
640 0           return($ReturnVal);
641             }
642              
643              
644              
645             ######### Utility routines ##########
646              
647             sub CompareHashKeys
648             {
649 0     0 0   my ($Hash1, $Hash2) = @_;
650              
651 0           my $In1NotIn2 = {}; @$In1NotIn2{keys %$Hash1 } = undef; delete @$In1NotIn2{keys %$Hash2 };
  0            
  0            
652 0           my $In2NotIn1 = {}; @$In2NotIn1{keys %$Hash2 } = undef; delete @$In2NotIn1{keys %$Hash1 };
  0            
  0            
653 0           my $Subset = {}; @$Subset {keys %$Hash1, keys %$Hash2} = undef; delete @$Subset {keys %$In1NotIn2, keys %$In2NotIn1};
  0            
  0            
654              
655 0           return($In1NotIn2, $In2NotIn1, $Subset);
656             }
657              
658             1;