Commit | Line | Data |
---|---|---|
f8881bd9 | 1 | package Devel::SelfStubber; |
d5201bd2 | 2 | use File::Spec; |
f8881bd9 AD |
3 | require SelfLoader; |
4 | @ISA = qw(SelfLoader); | |
73c78b0a | 5 | @EXPORT = 'AUTOLOAD'; |
f8881bd9 | 6 | $JUST_STUBS = 1; |
7f4f6daf | 7 | $VERSION = 1.03; |
a1457ef1 | 8 | sub Version {$VERSION} |
f8881bd9 AD |
9 | |
10 | # Use as | |
11 | # perl -e 'use Devel::SelfStubber;Devel::SelfStubber->stub(MODULE_NAME,LIB)' | |
12 | # (LIB defaults to '.') e.g. | |
13 | # perl -e 'use Devel::SelfStubber;Devel::SelfStubber->stub('Math::BigInt')' | |
14 | # would print out stubs needed if you added a __DATA__ before the subs. | |
15 | # Setting $Devel::SelfStubber::JUST_STUBS to 0 will print out the whole | |
16 | # module with the stubs entered just before the __DATA__ | |
17 | ||
18 | sub _add_to_cache { | |
19 | my($self,$fullname,$pack,$lines, $prototype) = @_; | |
20 | push(@DATA,@{$lines}); | |
21 | if($fullname){push(@STUBS,"sub $fullname $prototype;\n")}; # stubs | |
22 | '1;'; | |
23 | } | |
24 | ||
25 | sub _package_defined { | |
26 | my($self,$line) = @_; | |
27 | push(@DATA,$line); | |
28 | } | |
29 | ||
30 | sub stub { | |
31 | my($self,$module,$lib) = @_; | |
33235a50 | 32 | my($line,$end_data,$fh,$mod_file,$found_selfloader); |
d5201bd2 | 33 | $lib ||= File::Spec->curdir(); |
f8881bd9 | 34 | ($mod_file = $module) =~ s,::,/,g; |
d5201bd2 | 35 | $mod_file =~ tr|/|:| if $^O eq 'MacOS'; |
f8881bd9 | 36 | |
d5201bd2 | 37 | $mod_file = File::Spec->catfile($lib, "$mod_file.pm"); |
f8881bd9 | 38 | $fh = "${module}::DATA"; |
33235a50 | 39 | my (@BEFORE_DATA, @AFTER_DATA, @AFTER_END); |
7f4f6daf | 40 | @DATA = @STUBS = (); |
f8881bd9 AD |
41 | |
42 | open($fh,$mod_file) || die "Unable to open $mod_file"; | |
7f4f6daf | 43 | local $/ = "\n"; |
40da2db3 | 44 | while(defined ($line = <$fh>) and $line !~ m/^__DATA__/) { |
f8881bd9 AD |
45 | push(@BEFORE_DATA,$line); |
46 | $line =~ /use\s+SelfLoader/ && $found_selfloader++; | |
47 | } | |
7f4f6daf NC |
48 | (defined ($line) && $line =~ m/^__DATA__/) |
49 | || die "$mod_file doesn't contain a __DATA__ token"; | |
f8881bd9 AD |
50 | $found_selfloader || |
51 | print 'die "\'use SelfLoader;\' statement NOT FOUND!!\n"',"\n"; | |
33235a50 NC |
52 | if ($JUST_STUBS) { |
53 | $self->_load_stubs($module); | |
54 | } else { | |
55 | $self->_load_stubs($module, \@AFTER_END); | |
56 | } | |
f8881bd9 | 57 | if ( fileno($fh) ) { |
33235a50 | 58 | $end_data = 1; |
40da2db3 | 59 | while(defined($line = <$fh>)) { |
f8881bd9 AD |
60 | push(@AFTER_DATA,$line); |
61 | } | |
62 | } | |
1a36cb9f | 63 | close($fh); |
f8881bd9 AD |
64 | unless ($JUST_STUBS) { |
65 | print @BEFORE_DATA; | |
66 | } | |
67 | print @STUBS; | |
68 | unless ($JUST_STUBS) { | |
69 | print "1;\n__DATA__\n",@DATA; | |
33235a50 NC |
70 | if($end_data) { print "__END__ DATA\n",@AFTER_DATA; } |
71 | if(@AFTER_END) { print "__END__\n",@AFTER_END; } | |
f8881bd9 AD |
72 | } |
73 | } | |
74 | ||
75 | 1; | |
76 | __END__ | |
cb1a09d0 | 77 | |
f8881bd9 AD |
78 | =head1 NAME |
79 | ||
80 | Devel::SelfStubber - generate stubs for a SelfLoading module | |
81 | ||
82 | =head1 SYNOPSIS | |
83 | ||
84 | To generate just the stubs: | |
85 | ||
86 | use Devel::SelfStubber; | |
87 | Devel::SelfStubber->stub('MODULENAME','MY_LIB_DIR'); | |
88 | ||
89 | or to generate the whole module with stubs inserted correctly | |
90 | ||
91 | use Devel::SelfStubber; | |
92 | $Devel::SelfStubber::JUST_STUBS=0; | |
93 | Devel::SelfStubber->stub('MODULENAME','MY_LIB_DIR'); | |
94 | ||
95 | MODULENAME is the Perl module name, e.g. Devel::SelfStubber, | |
96 | NOT 'Devel/SelfStubber' or 'Devel/SelfStubber.pm'. | |
97 | ||
98 | MY_LIB_DIR defaults to '.' if not present. | |
99 | ||
100 | =head1 DESCRIPTION | |
101 | ||
102 | Devel::SelfStubber prints the stubs you need to put in the module | |
103 | before the __DATA__ token (or you can get it to print the entire | |
104 | module with stubs correctly placed). The stubs ensure that if | |
105 | a method is called, it will get loaded. They are needed specifically | |
106 | for inherited autoloaded methods. | |
107 | ||
108 | This is best explained using the following example: | |
109 | ||
110 | Assume four classes, A,B,C & D. | |
111 | ||
112 | A is the root class, B is a subclass of A, C is a subclass of B, | |
113 | and D is another subclass of A. | |
114 | ||
115 | A | |
116 | / \ | |
117 | B D | |
118 | / | |
119 | C | |
120 | ||
121 | If D calls an autoloaded method 'foo' which is defined in class A, | |
122 | then the method is loaded into class A, then executed. If C then | |
123 | calls method 'foo', and that method was reimplemented in class | |
124 | B, but set to be autoloaded, then the lookup mechanism never gets to | |
125 | the AUTOLOAD mechanism in B because it first finds the method | |
126 | already loaded in A, and so erroneously uses that. If the method | |
127 | foo had been stubbed in B, then the lookup mechanism would have | |
128 | found the stub, and correctly loaded and used the sub from B. | |
129 | ||
130 | So, for classes and subclasses to have inheritance correctly | |
131 | work with autoloading, you need to ensure stubs are loaded. | |
132 | ||
133 | The SelfLoader can load stubs automatically at module initialization | |
1fef88e7 | 134 | with the statement 'SelfLoader-E<gt>load_stubs()';, but you may wish to |
f8881bd9 AD |
135 | avoid having the stub loading overhead associated with your |
136 | initialization (though note that the SelfLoader::load_stubs method | |
137 | will be called sooner or later - at latest when the first sub | |
138 | is being autoloaded). In this case, you can put the sub stubs | |
139 | before the __DATA__ token. This can be done manually, but this | |
140 | module allows automatic generation of the stubs. | |
141 | ||
142 | By default it just prints the stubs, but you can set the | |
143 | global $Devel::SelfStubber::JUST_STUBS to 0 and it will | |
144 | print out the entire module with the stubs positioned correctly. | |
145 | ||
146 | At the very least, this is useful to see what the SelfLoader | |
147 | thinks are stubs - in order to ensure future versions of the | |
148 | SelfStubber remain in step with the SelfLoader, the | |
149 | SelfStubber actually uses the SelfLoader to determine which | |
150 | stubs are needed. | |
151 | ||
152 | =cut |