opener-tokenizer-base 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +148 -0
- data/bin/tokenizer-base +5 -0
- data/bin/tokenizer-de +5 -0
- data/bin/tokenizer-en +5 -0
- data/bin/tokenizer-es +5 -0
- data/bin/tokenizer-fr +5 -0
- data/bin/tokenizer-it +5 -0
- data/bin/tokenizer-nl +5 -0
- data/core/lib/Data/OptList.pm +256 -0
- data/core/lib/Params/Util.pm +866 -0
- data/core/lib/Sub/Exporter.pm +1101 -0
- data/core/lib/Sub/Exporter/Cookbook.pod +309 -0
- data/core/lib/Sub/Exporter/Tutorial.pod +280 -0
- data/core/lib/Sub/Exporter/Util.pm +354 -0
- data/core/lib/Sub/Install.pm +329 -0
- data/core/lib/Time/Stamp.pm +808 -0
- data/core/load-prefixes.pl +43 -0
- data/core/nonbreaking_prefixes/abbreviation_list.kaf +0 -0
- data/core/nonbreaking_prefixes/abbreviation_list.txt +444 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.ca +533 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.de +781 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.el +448 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.en +564 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.es +758 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.fr +1027 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.is +697 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.it +641 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.nl +739 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.pl +729 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.pt +656 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.ro +484 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.ru +705 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.sk +920 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.sl +524 -0
- data/core/nonbreaking_prefixes/nonbreaking_prefix.sv +492 -0
- data/core/split-sentences.pl +114 -0
- data/core/text-fixer.pl +169 -0
- data/core/tokenizer-cli.pl +363 -0
- data/core/tokenizer.pl +145 -0
- data/lib/opener/tokenizers/base.rb +84 -0
- data/lib/opener/tokenizers/base/version.rb +8 -0
- data/opener-tokenizer-base.gemspec +25 -0
- metadata +134 -0
@@ -0,0 +1,354 @@
|
|
1
|
+
use strict;
|
2
|
+
use warnings;
|
3
|
+
package Sub::Exporter::Util;
|
4
|
+
{
|
5
|
+
$Sub::Exporter::Util::VERSION = '0.984';
|
6
|
+
}
|
7
|
+
# ABSTRACT: utilities to make Sub::Exporter easier
|
8
|
+
|
9
|
+
use Data::OptList ();
|
10
|
+
use Params::Util ();
|
11
|
+
|
12
|
+
|
13
|
+
sub curry_method {
|
14
|
+
my $override_name = shift;
|
15
|
+
sub {
|
16
|
+
my ($class, $name) = @_;
|
17
|
+
$name = $override_name if defined $override_name;
|
18
|
+
sub { $class->$name(@_); };
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
BEGIN { *curry_class = \&curry_method; }
|
23
|
+
|
24
|
+
|
25
|
+
sub curry_chain {
|
26
|
+
# In the future, we can make \%arg an optional prepend, like the "special"
|
27
|
+
# args to the default Sub::Exporter-generated import routine.
|
28
|
+
my (@opt_list) = @_;
|
29
|
+
|
30
|
+
my $pairs = Data::OptList::mkopt(\@opt_list, 'args', 'ARRAY');
|
31
|
+
|
32
|
+
sub {
|
33
|
+
my ($class) = @_;
|
34
|
+
|
35
|
+
sub {
|
36
|
+
my $next = $class;
|
37
|
+
|
38
|
+
for my $i (0 .. $#$pairs) {
|
39
|
+
my $pair = $pairs->[ $i ];
|
40
|
+
|
41
|
+
unless (Params::Util::_INVOCANT($next)) { ## no critic Private
|
42
|
+
my $str = defined $next ? "'$next'" : 'undef';
|
43
|
+
Carp::croak("can't call $pair->[0] on non-invocant $str")
|
44
|
+
}
|
45
|
+
|
46
|
+
my ($method, $args) = @$pair;
|
47
|
+
|
48
|
+
if ($i == $#$pairs) {
|
49
|
+
return $next->$method($args ? @$args : ());
|
50
|
+
} else {
|
51
|
+
$next = $next->$method($args ? @$args : ());
|
52
|
+
}
|
53
|
+
}
|
54
|
+
};
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
# =head2 name_map
|
59
|
+
#
|
60
|
+
# This utility returns an list to be used in specify export generators. For
|
61
|
+
# example, the following:
|
62
|
+
#
|
63
|
+
# exports => {
|
64
|
+
# name_map(
|
65
|
+
# '_?_gen' => [ qw(fee fie) ],
|
66
|
+
# '_make_?' => [ qw(foo bar) ],
|
67
|
+
# ),
|
68
|
+
# }
|
69
|
+
#
|
70
|
+
# is equivalent to:
|
71
|
+
#
|
72
|
+
# exports => {
|
73
|
+
# name_map(
|
74
|
+
# fee => \'_fee_gen',
|
75
|
+
# fie => \'_fie_gen',
|
76
|
+
# foo => \'_make_foo',
|
77
|
+
# bar => \'_make_bar',
|
78
|
+
# ),
|
79
|
+
# }
|
80
|
+
#
|
81
|
+
# This can save a lot of typing, when providing many exports with similarly-named
|
82
|
+
# generators.
|
83
|
+
#
|
84
|
+
# =cut
|
85
|
+
#
|
86
|
+
# sub name_map {
|
87
|
+
# my (%groups) = @_;
|
88
|
+
#
|
89
|
+
# my %map;
|
90
|
+
#
|
91
|
+
# while (my ($template, $names) = each %groups) {
|
92
|
+
# for my $name (@$names) {
|
93
|
+
# (my $export = $template) =~ s/\?/$name/
|
94
|
+
# or Carp::croak 'no ? found in name_map template';
|
95
|
+
#
|
96
|
+
# $map{ $name } = \$export;
|
97
|
+
# }
|
98
|
+
# }
|
99
|
+
#
|
100
|
+
# return %map;
|
101
|
+
# }
|
102
|
+
|
103
|
+
|
104
|
+
sub merge_col {
|
105
|
+
my (%groups) = @_;
|
106
|
+
|
107
|
+
my %merged;
|
108
|
+
|
109
|
+
while (my ($default_name, $group) = each %groups) {
|
110
|
+
while (my ($export_name, $gen) = each %$group) {
|
111
|
+
$merged{$export_name} = sub {
|
112
|
+
my ($class, $name, $arg, $col) = @_;
|
113
|
+
|
114
|
+
my $merged_arg = exists $col->{$default_name}
|
115
|
+
? { %{ $col->{$default_name} }, %$arg }
|
116
|
+
: $arg;
|
117
|
+
|
118
|
+
if (Params::Util::_CODELIKE($gen)) { ## no critic Private
|
119
|
+
$gen->($class, $name, $merged_arg, $col);
|
120
|
+
} else {
|
121
|
+
$class->$$gen($name, $merged_arg, $col);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
return %merged;
|
128
|
+
}
|
129
|
+
|
130
|
+
|
131
|
+
sub __mixin_class_for {
|
132
|
+
my ($class, $mix_into) = @_;
|
133
|
+
require Package::Generator;
|
134
|
+
my $mixin_class = Package::Generator->new_package({
|
135
|
+
base => "$class\:\:__mixin__",
|
136
|
+
});
|
137
|
+
|
138
|
+
## no critic (ProhibitNoStrict)
|
139
|
+
no strict 'refs';
|
140
|
+
if (ref $mix_into) {
|
141
|
+
unshift @{"$mixin_class" . "::ISA"}, ref $mix_into;
|
142
|
+
} else {
|
143
|
+
unshift @{"$mix_into" . "::ISA"}, $mixin_class;
|
144
|
+
}
|
145
|
+
return $mixin_class;
|
146
|
+
}
|
147
|
+
|
148
|
+
sub mixin_installer {
|
149
|
+
sub {
|
150
|
+
my ($arg, $to_export) = @_;
|
151
|
+
|
152
|
+
my $mixin_class = __mixin_class_for($arg->{class}, $arg->{into});
|
153
|
+
bless $arg->{into} => $mixin_class if ref $arg->{into};
|
154
|
+
|
155
|
+
Sub::Exporter::default_installer(
|
156
|
+
{ %$arg, into => $mixin_class },
|
157
|
+
$to_export,
|
158
|
+
);
|
159
|
+
};
|
160
|
+
}
|
161
|
+
|
162
|
+
sub mixin_exporter {
|
163
|
+
Carp::cluck "mixin_exporter is deprecated; use mixin_installer instead; it behaves identically";
|
164
|
+
return mixin_installer;
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
sub like {
|
169
|
+
sub {
|
170
|
+
my ($value, $arg) = @_;
|
171
|
+
Carp::croak "no regex supplied to regex group generator" unless $value;
|
172
|
+
|
173
|
+
# Oh, qr//, how you bother me! See the p5p thread from around now about
|
174
|
+
# fixing this problem... too bad it won't help me. -- rjbs, 2006-04-25
|
175
|
+
my @values = eval { $value->isa('Regexp') } ? ($value, undef)
|
176
|
+
: @$value;
|
177
|
+
|
178
|
+
while (my ($re, $opt) = splice @values, 0, 2) {
|
179
|
+
Carp::croak "given pattern for regex group generater is not a Regexp"
|
180
|
+
unless eval { $re->isa('Regexp') };
|
181
|
+
my @exports = keys %{ $arg->{config}->{exports} };
|
182
|
+
my @matching = grep { $_ =~ $re } @exports;
|
183
|
+
|
184
|
+
my %merge = $opt ? %$opt : ();
|
185
|
+
my $prefix = (delete $merge{-prefix}) || '';
|
186
|
+
my $suffix = (delete $merge{-suffix}) || '';
|
187
|
+
|
188
|
+
for my $name (@matching) {
|
189
|
+
my $as = $prefix . $name . $suffix;
|
190
|
+
push @{ $arg->{import_args} }, [ $name => { %merge, -as => $as } ];
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
1;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
use Sub::Exporter -setup => {
|
199
|
+
exports => [ qw(
|
200
|
+
like
|
201
|
+
name_map
|
202
|
+
merge_col
|
203
|
+
curry_method curry_class
|
204
|
+
curry_chain
|
205
|
+
mixin_installer mixin_exporter
|
206
|
+
) ]
|
207
|
+
};
|
208
|
+
|
209
|
+
1;
|
210
|
+
|
211
|
+
__END__
|
212
|
+
=pod
|
213
|
+
|
214
|
+
=head1 NAME
|
215
|
+
|
216
|
+
Sub::Exporter::Util - utilities to make Sub::Exporter easier
|
217
|
+
|
218
|
+
=head1 VERSION
|
219
|
+
|
220
|
+
version 0.984
|
221
|
+
|
222
|
+
=head1 DESCRIPTION
|
223
|
+
|
224
|
+
This module provides a number of utility functions for performing common or
|
225
|
+
useful operations when setting up a Sub::Exporter configuration. All of the
|
226
|
+
utilites may be exported, but none are by default.
|
227
|
+
|
228
|
+
=head1 THE UTILITIES
|
229
|
+
|
230
|
+
=head2 curry_method
|
231
|
+
|
232
|
+
exports => {
|
233
|
+
some_method => curry_method,
|
234
|
+
}
|
235
|
+
|
236
|
+
This utility returns a generator which will produce an invocant-curried version
|
237
|
+
of a method. In other words, it will export a method call with the exporting
|
238
|
+
class built in as the invocant.
|
239
|
+
|
240
|
+
A module importing the code some the above example might do this:
|
241
|
+
|
242
|
+
use Some::Module qw(some_method);
|
243
|
+
|
244
|
+
my $x = some_method;
|
245
|
+
|
246
|
+
This would be equivalent to:
|
247
|
+
|
248
|
+
use Some::Module;
|
249
|
+
|
250
|
+
my $x = Some::Module->some_method;
|
251
|
+
|
252
|
+
If Some::Module is subclassed and the subclass's import method is called to
|
253
|
+
import C<some_method>, the subclass will be curried in as the invocant.
|
254
|
+
|
255
|
+
If an argument is provided for C<curry_method> it is used as the name of the
|
256
|
+
curried method to export. This means you could export a Widget constructor
|
257
|
+
like this:
|
258
|
+
|
259
|
+
exports => { widget => curry_method('new') }
|
260
|
+
|
261
|
+
This utility may also be called as C<curry_class>, for backwards compatibility.
|
262
|
+
|
263
|
+
=head2 curry_chain
|
264
|
+
|
265
|
+
C<curry_chain> behaves like C<L</curry_method>>, but is meant for generating
|
266
|
+
exports that will call several methods in succession.
|
267
|
+
|
268
|
+
exports => {
|
269
|
+
reticulate => curry_chain([
|
270
|
+
new => gather_data => analyze => [ detail => 100 ] => results
|
271
|
+
]),
|
272
|
+
}
|
273
|
+
|
274
|
+
If imported from Spliner, calling the C<reticulate> routine will be equivalent
|
275
|
+
to:
|
276
|
+
|
277
|
+
Splinter->new->gather_data->analyze(detail => 100)->results;
|
278
|
+
|
279
|
+
If any method returns something on which methods may not be called, the routine
|
280
|
+
croaks.
|
281
|
+
|
282
|
+
The arguments to C<curry_chain> form an optlist. The names are methods to be
|
283
|
+
called and the arguments, if given, are arrayrefs to be dereferenced and passed
|
284
|
+
as arguments to those methods. C<curry_chain> returns a generator like those
|
285
|
+
expected by Sub::Exporter.
|
286
|
+
|
287
|
+
B<Achtung!> at present, there is no way to pass arguments from the generated
|
288
|
+
routine to the method calls. This will probably be solved in future revisions
|
289
|
+
by allowing the opt list's values to be subroutines that will be called with
|
290
|
+
the generated routine's stack.
|
291
|
+
|
292
|
+
=head2 merge_col
|
293
|
+
|
294
|
+
exports => {
|
295
|
+
merge_col(defaults => {
|
296
|
+
twiddle => \'_twiddle_gen',
|
297
|
+
tweak => \&_tweak_gen,
|
298
|
+
}),
|
299
|
+
}
|
300
|
+
|
301
|
+
This utility wraps the given generator in one that will merge the named
|
302
|
+
collection into its args before calling it. This means that you can support a
|
303
|
+
"default" collector in multipe exports without writing the code each time.
|
304
|
+
|
305
|
+
You can specify as many pairs of collection names and generators as you like.
|
306
|
+
|
307
|
+
=head2 mixin_installer
|
308
|
+
|
309
|
+
use Sub::Exporter -setup => {
|
310
|
+
installer => Sub::Exporter::Util::mixin_installer,
|
311
|
+
exports => [ qw(foo bar baz) ],
|
312
|
+
};
|
313
|
+
|
314
|
+
This utility returns an installer that will install into a superclass and
|
315
|
+
adjust the ISA importing class to include the newly generated superclass.
|
316
|
+
|
317
|
+
If the target of importing is an object, the hierarchy is reversed: the new
|
318
|
+
class will be ISA the object's class, and the object will be reblessed.
|
319
|
+
|
320
|
+
B<Prerequisites>: This utility requires that Package::Generator be installed.
|
321
|
+
|
322
|
+
=head2 like
|
323
|
+
|
324
|
+
It's a collector that adds imports for anything like given regex.
|
325
|
+
|
326
|
+
If you provide this configuration:
|
327
|
+
|
328
|
+
exports => [ qw(igrep imap islurp exhausted) ],
|
329
|
+
collectors => { -like => Sub::Exporter::Util::like },
|
330
|
+
|
331
|
+
A user may import from your module like this:
|
332
|
+
|
333
|
+
use Your::Iterator -like => qr/^i/; # imports igre, imap, islurp
|
334
|
+
|
335
|
+
or
|
336
|
+
|
337
|
+
use Your::Iterator -like => [ qr/^i/ => { -prefix => 'your_' } ];
|
338
|
+
|
339
|
+
The group-like prefix and suffix arguments are respected; other arguments are
|
340
|
+
passed on to the generators for matching exports.
|
341
|
+
|
342
|
+
=head1 AUTHOR
|
343
|
+
|
344
|
+
Ricardo Signes <rjbs@cpan.org>
|
345
|
+
|
346
|
+
=head1 COPYRIGHT AND LICENSE
|
347
|
+
|
348
|
+
This software is copyright (c) 2007 by Ricardo Signes.
|
349
|
+
|
350
|
+
This is free software; you can redistribute it and/or modify it under
|
351
|
+
the same terms as the Perl 5 programming language system itself.
|
352
|
+
|
353
|
+
=cut
|
354
|
+
|
@@ -0,0 +1,329 @@
|
|
1
|
+
package Sub::Install;
|
2
|
+
|
3
|
+
use warnings;
|
4
|
+
use strict;
|
5
|
+
|
6
|
+
use Carp;
|
7
|
+
use Scalar::Util ();
|
8
|
+
|
9
|
+
=head1 NAME
|
10
|
+
|
11
|
+
Sub::Install - install subroutines into packages easily
|
12
|
+
|
13
|
+
=head1 VERSION
|
14
|
+
|
15
|
+
version 0.926
|
16
|
+
|
17
|
+
=cut
|
18
|
+
|
19
|
+
our $VERSION = '0.926';
|
20
|
+
|
21
|
+
=head1 SYNOPSIS
|
22
|
+
|
23
|
+
use Sub::Install;
|
24
|
+
|
25
|
+
Sub::Install::install_sub({
|
26
|
+
code => sub { ... },
|
27
|
+
into => $package,
|
28
|
+
as => $subname
|
29
|
+
});
|
30
|
+
|
31
|
+
=head1 DESCRIPTION
|
32
|
+
|
33
|
+
This module makes it easy to install subroutines into packages without the
|
34
|
+
unslightly mess of C<no strict> or typeglobs lying about where just anyone can
|
35
|
+
see them.
|
36
|
+
|
37
|
+
=head1 FUNCTIONS
|
38
|
+
|
39
|
+
=head2 install_sub
|
40
|
+
|
41
|
+
Sub::Install::install_sub({
|
42
|
+
code => \&subroutine,
|
43
|
+
into => "Finance::Shady",
|
44
|
+
as => 'launder',
|
45
|
+
});
|
46
|
+
|
47
|
+
This routine installs a given code reference into a package as a normal
|
48
|
+
subroutine. The above is equivalent to:
|
49
|
+
|
50
|
+
no strict 'refs';
|
51
|
+
*{"Finance::Shady" . '::' . "launder"} = \&subroutine;
|
52
|
+
|
53
|
+
If C<into> is not given, the sub is installed into the calling package.
|
54
|
+
|
55
|
+
If C<code> is not a code reference, it is looked for as an existing sub in the
|
56
|
+
package named in the C<from> parameter. If C<from> is not given, it will look
|
57
|
+
in the calling package.
|
58
|
+
|
59
|
+
If C<as> is not given, and if C<code> is a name, C<as> will default to C<code>.
|
60
|
+
If C<as> is not given, but if C<code> is a code ref, Sub::Install will try to
|
61
|
+
find the name of the given code ref and use that as C<as>.
|
62
|
+
|
63
|
+
That means that this code:
|
64
|
+
|
65
|
+
Sub::Install::install_sub({
|
66
|
+
code => 'twitch',
|
67
|
+
from => 'Person::InPain',
|
68
|
+
into => 'Person::Teenager',
|
69
|
+
as => 'dance',
|
70
|
+
});
|
71
|
+
|
72
|
+
is the same as:
|
73
|
+
|
74
|
+
package Person::Teenager;
|
75
|
+
|
76
|
+
Sub::Install::install_sub({
|
77
|
+
code => Person::InPain->can('twitch'),
|
78
|
+
as => 'dance',
|
79
|
+
});
|
80
|
+
|
81
|
+
=head2 reinstall_sub
|
82
|
+
|
83
|
+
This routine behaves exactly like C<L</install_sub>>, but does not emit a
|
84
|
+
warning if warnings are on and the destination is already defined.
|
85
|
+
|
86
|
+
=cut
|
87
|
+
|
88
|
+
sub _name_of_code {
|
89
|
+
my ($code) = @_;
|
90
|
+
require B;
|
91
|
+
my $name = B::svref_2object($code)->GV->NAME;
|
92
|
+
return $name unless $name =~ /\A__ANON__/;
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
96
|
+
# See also Params::Util, to which this code was donated.
|
97
|
+
sub _CODELIKE {
|
98
|
+
(Scalar::Util::reftype($_[0])||'') eq 'CODE'
|
99
|
+
|| Scalar::Util::blessed($_[0])
|
100
|
+
&& (overload::Method($_[0],'&{}') ? $_[0] : undef);
|
101
|
+
}
|
102
|
+
|
103
|
+
# do the heavy lifting
|
104
|
+
sub _build_public_installer {
|
105
|
+
my ($installer) = @_;
|
106
|
+
|
107
|
+
sub {
|
108
|
+
my ($arg) = @_;
|
109
|
+
my ($calling_pkg) = caller(0);
|
110
|
+
|
111
|
+
# I'd rather use ||= but I'm whoring for Devel::Cover.
|
112
|
+
for (qw(into from)) { $arg->{$_} = $calling_pkg unless $arg->{$_} }
|
113
|
+
|
114
|
+
# This is the only absolutely required argument, in many cases.
|
115
|
+
Carp::croak "named argument 'code' is not optional" unless $arg->{code};
|
116
|
+
|
117
|
+
if (_CODELIKE($arg->{code})) {
|
118
|
+
$arg->{as} ||= _name_of_code($arg->{code});
|
119
|
+
} else {
|
120
|
+
Carp::croak
|
121
|
+
"couldn't find subroutine named $arg->{code} in package $arg->{from}"
|
122
|
+
unless my $code = $arg->{from}->can($arg->{code});
|
123
|
+
|
124
|
+
$arg->{as} = $arg->{code} unless $arg->{as};
|
125
|
+
$arg->{code} = $code;
|
126
|
+
}
|
127
|
+
|
128
|
+
Carp::croak "couldn't determine name under which to install subroutine"
|
129
|
+
unless $arg->{as};
|
130
|
+
|
131
|
+
$installer->(@$arg{qw(into as code) });
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
# do the ugly work
|
136
|
+
|
137
|
+
my $_misc_warn_re;
|
138
|
+
my $_redef_warn_re;
|
139
|
+
BEGIN {
|
140
|
+
$_misc_warn_re = qr/
|
141
|
+
Prototype\ mismatch:\ sub\ .+? |
|
142
|
+
Constant subroutine \S+ redefined
|
143
|
+
/x;
|
144
|
+
$_redef_warn_re = qr/Subroutine\ \S+\ redefined/x;
|
145
|
+
}
|
146
|
+
|
147
|
+
my $eow_re;
|
148
|
+
BEGIN { $eow_re = qr/ at .+? line \d+\.\Z/ };
|
149
|
+
|
150
|
+
sub _do_with_warn {
|
151
|
+
my ($arg) = @_;
|
152
|
+
my $code = delete $arg->{code};
|
153
|
+
my $wants_code = sub {
|
154
|
+
my $code = shift;
|
155
|
+
sub {
|
156
|
+
my $warn = $SIG{__WARN__} ? $SIG{__WARN__} : sub { warn @_ }; ## no critic
|
157
|
+
local $SIG{__WARN__} = sub {
|
158
|
+
my ($error) = @_;
|
159
|
+
for (@{ $arg->{suppress} }) {
|
160
|
+
return if $error =~ $_;
|
161
|
+
}
|
162
|
+
for (@{ $arg->{croak} }) {
|
163
|
+
if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
|
164
|
+
Carp::croak $base_error;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
for (@{ $arg->{carp} }) {
|
168
|
+
if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
|
169
|
+
return $warn->(Carp::shortmess $base_error);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
($arg->{default} || $warn)->($error);
|
173
|
+
};
|
174
|
+
$code->(@_);
|
175
|
+
};
|
176
|
+
};
|
177
|
+
return $wants_code->($code) if $code;
|
178
|
+
return $wants_code;
|
179
|
+
}
|
180
|
+
|
181
|
+
sub _installer {
|
182
|
+
sub {
|
183
|
+
my ($pkg, $name, $code) = @_;
|
184
|
+
no strict 'refs'; ## no critic ProhibitNoStrict
|
185
|
+
*{"$pkg\::$name"} = $code;
|
186
|
+
return $code;
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
BEGIN {
|
191
|
+
*_ignore_warnings = _do_with_warn({
|
192
|
+
carp => [ $_misc_warn_re, $_redef_warn_re ]
|
193
|
+
});
|
194
|
+
|
195
|
+
*install_sub = _build_public_installer(_ignore_warnings(_installer));
|
196
|
+
|
197
|
+
*_carp_warnings = _do_with_warn({
|
198
|
+
carp => [ $_misc_warn_re ],
|
199
|
+
suppress => [ $_redef_warn_re ],
|
200
|
+
});
|
201
|
+
|
202
|
+
*reinstall_sub = _build_public_installer(_carp_warnings(_installer));
|
203
|
+
|
204
|
+
*_install_fatal = _do_with_warn({
|
205
|
+
code => _installer,
|
206
|
+
croak => [ $_redef_warn_re ],
|
207
|
+
});
|
208
|
+
}
|
209
|
+
|
210
|
+
=head2 install_installers
|
211
|
+
|
212
|
+
This routine is provided to allow Sub::Install compatibility with
|
213
|
+
Sub::Installer. It installs C<install_sub> and C<reinstall_sub> methods into
|
214
|
+
the package named by its argument.
|
215
|
+
|
216
|
+
Sub::Install::install_installers('Code::Builder'); # just for us, please
|
217
|
+
Code::Builder->install_sub({ name => $code_ref });
|
218
|
+
|
219
|
+
Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
|
220
|
+
Anything::At::All->install_sub({ name => $code_ref });
|
221
|
+
|
222
|
+
The installed installers are similar, but not identical, to those provided by
|
223
|
+
Sub::Installer. They accept a single hash as an argument. The key/value pairs
|
224
|
+
are used as the C<as> and C<code> parameters to the C<install_sub> routine
|
225
|
+
detailed above. The package name on which the method is called is used as the
|
226
|
+
C<into> parameter.
|
227
|
+
|
228
|
+
Unlike Sub::Installer's C<install_sub> will not eval strings into code, but
|
229
|
+
will look for named code in the calling package.
|
230
|
+
|
231
|
+
=cut
|
232
|
+
|
233
|
+
sub install_installers {
|
234
|
+
my ($into) = @_;
|
235
|
+
|
236
|
+
for my $method (qw(install_sub reinstall_sub)) {
|
237
|
+
my $code = sub {
|
238
|
+
my ($package, $subs) = @_;
|
239
|
+
my ($caller) = caller(0);
|
240
|
+
my $return;
|
241
|
+
for (my ($name, $sub) = %$subs) {
|
242
|
+
$return = Sub::Install->can($method)->({
|
243
|
+
code => $sub,
|
244
|
+
from => $caller,
|
245
|
+
into => $package,
|
246
|
+
as => $name
|
247
|
+
});
|
248
|
+
}
|
249
|
+
return $return;
|
250
|
+
};
|
251
|
+
install_sub({ code => $code, into => $into, as => $method });
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
=head1 EXPORTS
|
256
|
+
|
257
|
+
Sub::Install exports C<install_sub> and C<reinstall_sub> only if they are
|
258
|
+
requested.
|
259
|
+
|
260
|
+
=head2 exporter
|
261
|
+
|
262
|
+
Sub::Install has a never-exported subroutine called C<exporter>, which is used
|
263
|
+
to implement its C<import> routine. It takes a hashref of named arguments,
|
264
|
+
only one of which is currently recognize: C<exports>. This must be an arrayref
|
265
|
+
of subroutines to offer for export.
|
266
|
+
|
267
|
+
This routine is mainly for Sub::Install's own consumption. Instead, consider
|
268
|
+
L<Sub::Exporter>.
|
269
|
+
|
270
|
+
=cut
|
271
|
+
|
272
|
+
sub exporter {
|
273
|
+
my ($arg) = @_;
|
274
|
+
|
275
|
+
my %is_exported = map { $_ => undef } @{ $arg->{exports} };
|
276
|
+
|
277
|
+
sub {
|
278
|
+
my $class = shift;
|
279
|
+
my $target = caller;
|
280
|
+
for (@_) {
|
281
|
+
Carp::croak "'$_' is not exported by $class" if !exists $is_exported{$_};
|
282
|
+
install_sub({ code => $_, from => $class, into => $target });
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
BEGIN { *import = exporter({ exports => [ qw(install_sub reinstall_sub) ] }); }
|
288
|
+
|
289
|
+
=head1 SEE ALSO
|
290
|
+
|
291
|
+
=over
|
292
|
+
|
293
|
+
=item L<Sub::Installer>
|
294
|
+
|
295
|
+
This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
|
296
|
+
does the same thing, but does it by getting its greasy fingers all over
|
297
|
+
UNIVERSAL. I was really happy about the idea of making the installation of
|
298
|
+
coderefs less ugly, but I couldn't bring myself to replace the ugliness of
|
299
|
+
typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
|
300
|
+
|
301
|
+
=item L<Sub::Exporter>
|
302
|
+
|
303
|
+
This is a complete Exporter.pm replacement, built atop Sub::Install.
|
304
|
+
|
305
|
+
=back
|
306
|
+
|
307
|
+
=head1 AUTHOR
|
308
|
+
|
309
|
+
Ricardo Signes, C<< <rjbs@cpan.org> >>
|
310
|
+
|
311
|
+
Several of the tests are adapted from tests that shipped with Damian Conway's
|
312
|
+
Sub-Installer distribution.
|
313
|
+
|
314
|
+
=head1 BUGS
|
315
|
+
|
316
|
+
Please report any bugs or feature requests through the web interface at
|
317
|
+
L<http://rt.cpan.org>. I will be notified, and then you'll automatically be
|
318
|
+
notified of progress on your bug as I make changes.
|
319
|
+
|
320
|
+
=head1 COPYRIGHT
|
321
|
+
|
322
|
+
Copyright 2005-2006 Ricardo Signes, All Rights Reserved.
|
323
|
+
|
324
|
+
This program is free software; you can redistribute it and/or modify it
|
325
|
+
under the same terms as Perl itself.
|
326
|
+
|
327
|
+
=cut
|
328
|
+
|
329
|
+
1;
|