Checking in changes prior to tagging of version 0.93. Changelog diff is:
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
6d0815b5 6our $VERSION = '0.93';
ae18d5ec 7$VERSION = eval $VERSION;
8our $AUTHORITY = 'cpan:STEVAN';
9
e606ae5f 10use Class::MOP;
11use List::MoreUtils qw( first_index uniq );
12use Moose::Util::MetaRole;
091ac4b7 13use Sub::Exporter 0.980;
9f2230e9 14use Sub::Name qw(subname);
e606ae5f 15
16my %EXPORT_SPEC;
17
18sub setup_import_methods {
19 my ( $class, %args ) = @_;
20
21 my $exporting_package = $args{exporting_package} ||= caller();
22
95056a1e 23 $class->build_import_methods(
24 %args,
25 install => [qw(import unimport init_meta)]
26 );
e606ae5f 27}
28
29sub build_import_methods {
30 my ( $class, %args ) = @_;
31
32 my $exporting_package = $args{exporting_package} ||= caller();
33
34 $EXPORT_SPEC{$exporting_package} = \%args;
35
36 my @exports_from = $class->_follow_also( $exporting_package );
37
38 my $export_recorder = {};
39
0661fc1a 40 my ( $exports, $is_removable )
e05fb8ae 41 = $class->_make_sub_exporter_params(
f44ec924 42 [ @exports_from, $exporting_package ], $export_recorder );
e606ae5f 43
44 my $exporter = Sub::Exporter::build_exporter(
45 {
46 exports => $exports,
0661fc1a 47 groups => { default => [':all'] }
e606ae5f 48 }
49 );
50
95056a1e 51 my %methods;
e606ae5f 52 # $args{_export_to_main} exists for backwards compat, because
53 # Moose::Util::TypeConstraints did export to main (unlike Moose &
54 # Moose::Role).
95056a1e 55 $methods{import} = $class->_make_import_sub( $exporting_package,
56 $exporter, \@exports_from, $args{_export_to_main} );
e606ae5f 57
95056a1e 58 $methods{unimport} = $class->_make_unimport_sub( $exporting_package,
59 $exports, $is_removable, $export_recorder );
60
61 $methods{init_meta} = $class->_make_init_meta( $exporting_package,
62 \%args );
63
64 my $package = Class::MOP::Package->initialize($exporting_package);
906eabcd 65 for my $to_install ( @{ $args{install} || [] } ) {
95056a1e 66 my $symbol = '&' . $to_install;
906eabcd 67 next
68 unless $methods{$to_install}
69 && !$package->has_package_symbol($symbol);
70 $package->add_package_symbol( $symbol, $methods{$to_install} );
95056a1e 71 }
e606ae5f 72
95056a1e 73 return ( $methods{import}, $methods{unimport}, $methods{init_meta} )
e606ae5f 74}
75
76{
77 my $seen = {};
78
79 sub _follow_also {
80 my $class = shift;
81 my $exporting_package = shift;
82
83 local %$seen = ( $exporting_package => 1 );
84
85 return uniq( _follow_also_real($exporting_package) );
86 }
87
88 sub _follow_also_real {
89 my $exporting_package = shift;
90
ba1a3c2f 91 if (!exists $EXPORT_SPEC{$exporting_package}) {
92 my $loaded = Class::MOP::is_class_loaded($exporting_package);
93
94 die "Package in also ($exporting_package) does not seem to "
95 . "use Moose::Exporter"
96 . ($loaded ? "" : " (is it loaded?)");
97 }
e606ae5f 98
99 my $also = $EXPORT_SPEC{$exporting_package}{also};
100
101 return unless defined $also;
102
103 my @also = ref $also ? @{$also} : $also;
104
105 for my $package (@also)
106 {
b822369d 107 die "Circular reference in 'also' parameter to Moose::Exporter between $exporting_package and $package"
e606ae5f 108 if $seen->{$package};
109
110 $seen->{$package} = 1;
111 }
112
113 return @also, map { _follow_also_real($_) } @also;
114 }
115}
116
117sub _make_sub_exporter_params {
118 my $class = shift;
119 my $packages = shift;
120 my $export_recorder = shift;
121
122 my %exports;
e05fb8ae 123 my %is_removable;
e606ae5f 124
125 for my $package ( @{$packages} ) {
126 my $args = $EXPORT_SPEC{$package}
127 or die "The $package package does not use Moose::Exporter\n";
128
5ac14e89 129 for my $name ( @{ $args->{with_meta} } ) {
0dd4228e 130 my $sub = $class->_sub_from_package( $package, $name )
131 or next;
e6a5040f 132
e606ae5f 133 my $fq_name = $package . '::' . $name;
134
5ac14e89 135 $exports{$name} = $class->_make_wrapped_sub_with_meta(
e606ae5f 136 $fq_name,
137 $sub,
138 $export_recorder,
139 );
e05fb8ae 140
141 $is_removable{$name} = 1;
e606ae5f 142 }
143
5ac14e89 144 for my $name ( @{ $args->{with_caller} } ) {
0dd4228e 145 my $sub = $class->_sub_from_package( $package, $name )
146 or next;
e6a5040f 147
45975bce 148 my $fq_name = $package . '::' . $name;
149
5ac14e89 150 $exports{$name} = $class->_make_wrapped_sub(
45975bce 151 $fq_name,
152 $sub,
153 $export_recorder,
154 );
155
156 $is_removable{$name} = 1;
157 }
158
e606ae5f 159 for my $name ( @{ $args->{as_is} } ) {
e6a5040f 160 my ($sub, $coderef_name);
e606ae5f 161
162 if ( ref $name ) {
163 $sub = $name;
e05fb8ae 164
165 # Even though Moose re-exports things from Carp &
166 # Scalar::Util, we don't want to remove those at
167 # unimport time, because the importing package may
168 # have imported them explicitly ala
169 #
170 # use Carp qw( confess );
171 #
172 # This is a hack. Since we can't know whether they
173 # really want to keep these subs or not, we err on the
174 # safe side and leave them in.
175 my $coderef_pkg;
e6a5040f 176 ( $coderef_pkg, $coderef_name )
177 = Class::MOP::get_code_info($name);
e05fb8ae 178
e6a5040f 179 $is_removable{$coderef_name} = $coderef_pkg eq $package ? 1 : 0;
e606ae5f 180 }
181 else {
0dd4228e 182 $sub = $class->_sub_from_package( $package, $name )
183 or next;
e6a5040f 184
e05fb8ae 185 $is_removable{$name} = 1;
e6a5040f 186 $coderef_name = $name;
e606ae5f 187 }
188
189 $export_recorder->{$sub} = 1;
190
e6a5040f 191 $exports{$coderef_name} = sub {$sub};
e606ae5f 192 }
193 }
194
0661fc1a 195 return ( \%exports, \%is_removable );
e606ae5f 196}
197
0dd4228e 198sub _sub_from_package {
199 my $sclass = shift;
200 my $package = shift;
201 my $name = shift;
202
203 my $sub = do {
204 no strict 'refs';
205 \&{ $package . '::' . $name };
206 };
207
208 return $sub if defined &$sub;
209
210 Carp::cluck
211 "Trying to export undefined sub ${package}::${name}";
212
213 return;
214}
215
96bb13ea 216our $CALLER;
217
218sub _make_wrapped_sub {
b4f00a34 219 my $self = shift;
96bb13ea 220 my $fq_name = shift;
221 my $sub = shift;
222 my $export_recorder = shift;
223
224 # We need to set the package at import time, so that when
225 # package Foo imports has(), we capture "Foo" as the
226 # package. This lets other packages call Foo::has() and get
227 # the right package. This is done for backwards compatibility
228 # with existing production code, not because this is a good
229 # idea ;)
230 return sub {
231 my $caller = $CALLER;
232
6de00734 233 my $wrapper = $self->_curry_wrapper($sub, $fq_name, $caller);
b4f00a34 234
9f2230e9 235 my $sub = subname($fq_name => $wrapper);
96bb13ea 236
237 $export_recorder->{$sub} = 1;
238
239 return $sub;
240 };
241}
e606ae5f 242
45975bce 243sub _make_wrapped_sub_with_meta {
244 my $self = shift;
245 my $fq_name = shift;
246 my $sub = shift;
247 my $export_recorder = shift;
248
249 return sub {
250 my $caller = $CALLER;
251
252 my $wrapper = $self->_late_curry_wrapper($sub, $fq_name,
253 sub { Class::MOP::class_of(shift) } => $caller);
254
255 my $sub = subname($fq_name => $wrapper);
256
257 $export_recorder->{$sub} = 1;
258
259 return $sub;
260 };
261}
262
6de00734 263sub _curry_wrapper {
badbc528 264 my $class = shift;
b4f00a34 265 my $sub = shift;
266 my $fq_name = shift;
6de00734 267 my @extra = @_;
b4f00a34 268
6de00734 269 my $wrapper = sub { $sub->(@extra, @_) };
badbc528 270 if (my $proto = prototype $sub) {
2d7e979b 271 # XXX - Perl's prototype sucks. Use & to make set_prototype
6de00734 272 # ignore the fact that we're passing "private variables"
2d7e979b 273 &Scalar::Util::set_prototype($wrapper, $proto);
badbc528 274 }
275 return $wrapper;
b4f00a34 276}
277
45975bce 278sub _late_curry_wrapper {
279 my $class = shift;
280 my $sub = shift;
281 my $fq_name = shift;
282 my $extra = shift;
283 my @ex_args = @_;
284
285 my $wrapper = sub {
286 # resolve curried arguments at runtime via this closure
287 my @curry = ( $extra->( @ex_args ) );
288 return $sub->(@curry, @_);
289 };
290
291 if (my $proto = prototype $sub) {
292 # XXX - Perl's prototype sucks. Use & to make set_prototype
293 # ignore the fact that we're passing "private variables"
294 &Scalar::Util::set_prototype($wrapper, $proto);
295 }
296 return $wrapper;
297}
298
96bb13ea 299sub _make_import_sub {
300 shift;
301 my $exporting_package = shift;
302 my $exporter = shift;
303 my $exports_from = shift;
96bb13ea 304
305 return sub {
306
307 # I think we could use Sub::Exporter's collector feature
308 # to do this, but that would be rather gross, since that
309 # feature isn't really designed to return a value to the
310 # caller of the exporter sub.
311 #
312 # Also, this makes sure we preserve backwards compat for
313 # _get_caller, so it always sees the arguments in the
314 # expected order.
315 my $traits;
316 ( $traits, @_ ) = _strip_traits(@_);
317
8f30b86e 318 my $metaclass;
319 ( $metaclass, @_ ) = _strip_metaclass(@_);
8a8856de 320 $metaclass = Moose::Util::resolve_metaclass_alias(
321 'Class' => $metaclass
322 ) if defined $metaclass && length $metaclass;
8f30b86e 323
96bb13ea 324 # Normally we could look at $_[0], but in some weird cases
325 # (involving goto &Moose::import), $_[0] ends as something
326 # else (like Squirrel).
327 my $class = $exporting_package;
328
329 $CALLER = _get_caller(@_);
330
331 # this works because both pragmas set $^H (see perldoc
332 # perlvar) which affects the current compilation -
333 # i.e. the file who use'd us - which is why we don't need
334 # to do anything special to make it affect that file
335 # rather than this one (which is already compiled)
336
337 strict->import;
338 warnings->import;
339
96bb13ea 340 my $did_init_meta;
341 for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
816208bc 342 # init_meta can apply a role, which when loaded uses
343 # Moose::Exporter, which in turn sets $CALLER, so we need
344 # to protect against that.
fdeb8354 345 local $CALLER = $CALLER;
89bcd625 346 $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
96bb13ea 347 $did_init_meta = 1;
348 }
e606ae5f 349
96bb13ea 350 if ( $did_init_meta && @{$traits} ) {
351 # The traits will use Moose::Role, which in turn uses
352 # Moose::Exporter, which in turn sets $CALLER, so we need
353 # to protect against that.
354 local $CALLER = $CALLER;
355 _apply_meta_traits( $CALLER, $traits );
356 }
357 elsif ( @{$traits} ) {
70ea9161 358 require Moose;
96bb13ea 359 Moose->throw_error(
360 "Cannot provide traits when $class does not have an init_meta() method"
361 );
362 }
e606ae5f 363
96bb13ea 364 goto $exporter;
365 };
e606ae5f 366}
367
96bb13ea 368
e606ae5f 369sub _strip_traits {
370 my $idx = first_index { $_ eq '-traits' } @_;
371
372 return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
373
374 my $traits = $_[ $idx + 1 ];
375
376 splice @_, $idx, 2;
377
378 $traits = [ $traits ] unless ref $traits;
379
380 return ( $traits, @_ );
381}
382
8f30b86e 383sub _strip_metaclass {
384 my $idx = first_index { $_ eq '-metaclass' } @_;
385
386 return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
387
388 my $metaclass = $_[ $idx + 1 ];
389
390 splice @_, $idx, 2;
391
392 return ( $metaclass, @_ );
393}
394
e606ae5f 395sub _apply_meta_traits {
396 my ( $class, $traits ) = @_;
397
398 return unless @{$traits};
399
2571a16d 400 my $meta = Class::MOP::class_of($class);
e606ae5f 401
402 my $type = ( split /::/, ref $meta )[-1]
c245d69b 403 or Moose->throw_error(
e606ae5f 404 'Cannot determine metaclass type for trait application . Meta isa '
4c0b3599 405 . ref $meta );
e606ae5f 406
407 my @resolved_traits
386c056b 408 = map {
409 ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
410 }
e606ae5f 411 @$traits;
412
413 return unless @resolved_traits;
414
415 Moose::Util::MetaRole::apply_metaclass_roles(
416 for_class => $class,
417 metaclass_roles => \@resolved_traits,
418 );
419}
420
421sub _get_caller {
422 # 1 extra level because it's called by import so there's a layer
423 # of indirection
424 my $offset = 1;
425
426 return
427 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
428 : ( ref $_[1] && defined $_[1]->{into_level} )
429 ? caller( $offset + $_[1]->{into_level} )
430 : caller($offset);
431}
432
433sub _make_unimport_sub {
434 shift;
435 my $exporting_package = shift;
436 my $exports = shift;
e05fb8ae 437 my $is_removable = shift;
e606ae5f 438 my $export_recorder = shift;
439
440 return sub {
441 my $caller = scalar caller();
442 Moose::Exporter->_remove_keywords(
443 $caller,
444 [ keys %{$exports} ],
e05fb8ae 445 $is_removable,
e606ae5f 446 $export_recorder,
447 );
448 };
449}
450
451sub _remove_keywords {
452 shift;
453 my $package = shift;
454 my $keywords = shift;
e05fb8ae 455 my $is_removable = shift;
e606ae5f 456 my $recorded_exports = shift;
457
458 no strict 'refs';
459
460 foreach my $name ( @{ $keywords } ) {
e05fb8ae 461 next unless $is_removable->{$name};
e606ae5f 462
463 if ( defined &{ $package . '::' . $name } ) {
464 my $sub = \&{ $package . '::' . $name };
465
466 # make sure it is from us
467 next unless $recorded_exports->{$sub};
468
469 # and if it is from us, then undef the slot
470 delete ${ $package . '::' }{$name};
471 }
472 }
473}
474
95056a1e 475sub _make_init_meta {
476 shift;
906eabcd 477 my $class = shift;
478 my $args = shift;
95056a1e 479
480 my %metaclass_roles;
906eabcd 481 for my $role (
482 map {"${_}_roles"}
483 qw(metaclass
484 attribute_metaclass
485 method_metaclass
486 wrapped_method_metaclass
487 instance_metaclass
488 constructor_class
489 destructor_class
490 error_class
491 application_to_class_class
492 application_to_role_class
493 application_to_instance_class)
494 ) {
95056a1e 495 $metaclass_roles{$role} = $args->{$role} if exists $args->{$role};
496 }
497
498 my %base_class_roles;
906eabcd 499 %base_class_roles = ( roles => $args->{base_class_roles} )
95056a1e 500 if exists $args->{base_class_roles};
501
502 return unless %metaclass_roles || %base_class_roles;
503
504 return sub {
505 shift;
506 my %options = @_;
906eabcd 507
508 return unless Class::MOP::class_of( $options{for_class} );
509
95056a1e 510 Moose::Util::MetaRole::apply_metaclass_roles(
511 for_class => $options{for_class},
512 %metaclass_roles,
513 );
906eabcd 514
95056a1e 515 Moose::Util::MetaRole::apply_base_class_roles(
516 for_class => $options{for_class},
517 %base_class_roles,
906eabcd 518 )
519 if Class::MOP::class_of( $options{for_class} )
520 ->isa('Moose::Meta::Class');
521
522 return Class::MOP::class_of( $options{for_class} );
95056a1e 523 };
524}
525
e2fa092d 526sub import {
527 strict->import;
528 warnings->import;
529}
530
e606ae5f 5311;
532
533__END__
534
535=head1 NAME
536
537Moose::Exporter - make an import() and unimport() just like Moose.pm
538
539=head1 SYNOPSIS
540
541 package MyApp::Moose;
542
e606ae5f 543 use Moose ();
544 use Moose::Exporter;
545
546 Moose::Exporter->setup_import_methods(
5ac14e89 547 with_meta => [ 'has_rw', 'sugar2' ],
548 as_is => [ 'sugar3', \&Some::Random::thing ],
549 also => 'Moose',
e606ae5f 550 );
551
82ad7804 552 sub has_rw {
5ac14e89 553 my ( $meta, $name, %options ) = @_;
554 $meta->add_attribute(
555 $name,
82ad7804 556 is => 'rw',
557 %options,
558 );
559 }
560
e606ae5f 561 # then later ...
562 package MyApp::User;
563
564 use MyApp::Moose;
565
566 has 'name';
6daad0b9 567 has_rw 'size';
e606ae5f 568 thing;
569
570 no MyApp::Moose;
571
572=head1 DESCRIPTION
573
fd7ab111 574This module encapsulates the exporting of sugar functions in a
95056a1e 575C<Moose.pm>-like manner. It does this by building custom C<import>,
37e4fe95 576C<unimport>, and C<init_meta> methods for your module, based on a spec you
577provide.
e606ae5f 578
37e4fe95 579It also lets you "stack" Moose-alike modules so you can export Moose's sugar
580as well as your own, along with sugar from any random C<MooseX> module, as
581long as they all use C<Moose::Exporter>. This feature exists to let you bundle
582a set of MooseX modules into a policy module that developers can use directly
583instead of using Moose itself.
e606ae5f 584
10e0127a 585To simplify writing exporter modules, C<Moose::Exporter> also imports
586C<strict> and C<warnings> into your exporter module, as well as into
587modules that use it.
588
e606ae5f 589=head1 METHODS
590
591This module provides two public methods:
592
4b68e0de 593=over 4
594
595=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 596
95056a1e 597When you call this method, C<Moose::Exporter> builds custom C<import>,
37e4fe95 598C<unimport>, and C<init_meta> methods for your module. The C<import> method
599will export the functions you specify, and can also re-export functions
600exported by some other module (like C<Moose.pm>).
e606ae5f 601
37e4fe95 602The C<unimport> method cleans the caller's namespace of all the exported
603functions.
e606ae5f 604
37e4fe95 605If you pass any parameters for L<Moose::Util::MetaRole>, this method will
606generate an C<init_meta> for you as well (see below for details). This
607C<init_meta> will call C<Moose::Util::MetaRole::apply_metaclass_roles> and
608C<Moose::Util::MetaRole::apply_base_class_roles> as needed.
95056a1e 609
610Note that if any of these methods already exist, they will not be
611overridden, you will have to use C<build_import_methods> to get the
612coderef that would be installed.
e606ae5f 613
614This method accepts the following parameters:
615
4b68e0de 616=over 8
e606ae5f 617
5ac14e89 618=item * with_meta => [ ... ]
e606ae5f 619
37e4fe95 620This list of function I<names only> will be wrapped and then exported. The
5ac14e89 621wrapper will pass the metaclass object for the caller as its first argument.
622
623Many sugar functions will need to use this metaclass object to do something to
624the calling package.
e606ae5f 625
626=item * as_is => [ ... ]
627
37e4fe95 628This list of function names or sub references will be exported as-is. You can
629identify a subroutine by reference, which is handy to re-export some other
630module's functions directly by reference (C<\&Some::Package::function>).
e606ae5f 631
37e4fe95 632If you do export some other package's function, this function will never be
633removed by the C<unimport> method. The reason for this is we cannot know if
634the caller I<also> explicitly imported the sub themselves, and therefore wants
635to keep it.
e05fb8ae 636
e606ae5f 637=item * also => $name or \@names
638
639This is a list of modules which contain functions that the caller
640wants to export. These modules must also use C<Moose::Exporter>. The
641most common use case will be to export the functions from C<Moose.pm>.
5ac14e89 642Functions specified by C<with_meta> or C<as_is> take precedence over
ae8817b6 643functions exported by modules specified by C<also>, so that a module
644can selectively override functions exported by another module.
e606ae5f 645
646C<Moose::Exporter> also makes sure all these functions get removed
647when C<unimport> is called.
648
649=back
650
95056a1e 651Any of the C<*_roles> options for
37e4fe95 652C<Moose::Util::MetaRole::apply_metaclass_roles> and
653C<Moose::Util::MetaRole::base_class_roles> are also acceptable.
95056a1e 654
4b68e0de 655=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 656
95056a1e 657Returns two or three code refs, one for C<import>, one for
658C<unimport>, and optionally one for C<init_meta>, if the appropriate
659options are passed in.
660
37e4fe95 661Accepts the additional C<install> option, which accepts an arrayref of method
662names to install into your exporting package. The valid options are C<import>,
663C<unimport>, and C<init_meta>. Calling C<setup_import_methods> is equivalent
664to calling C<build_import_methods> with C<< install => [qw(import unimport
665init_meta)] >> except that it doesn't also return the methods.
e606ae5f 666
667Used by C<setup_import_methods>.
668
4b68e0de 669=back
670
e606ae5f 671=head1 IMPORTING AND init_meta
672
37e4fe95 673If you want to set an alternative base object class or metaclass class, see
674above for details on how this module can call L<Moose::Util::MetaRole> for
675you.
676
677If you want to do something that is not supported by this module, simply
678define an C<init_meta> method in your class. The C<import> method that
679C<Moose::Exporter> generates for you will call this method (if it exists). It
680will always pass the caller to this method via the C<for_class> parameter.
e606ae5f 681
682Most of the time, your C<init_meta> method will probably just call C<<
683Moose->init_meta >> to do the real work:
684
685 sub init_meta {
686 shift; # our class name
687 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
688 }
689
95056a1e 690Keep in mind that C<build_import_methods> will return an C<init_meta>
691method for you, which you can also call from within your custom
37e4fe95 692C<init_meta>:
693
694 my ( $import, $unimport, $init_meta ) =
695 Moose::Exporter->build_import_methods( ... );
696
697 sub import {
698 my $class = shift;
699
700 ...
701
702 $class->$import(...);
703
704 ...
705 }
706
707 sub unimport { goto &$unimport }
708
709 sub init_meta {
710 my $class = shift;
711
712 ...
713
714 $class->$init_meta(...);
715
716 ...
717 }
95056a1e 718
e606ae5f 719=head1 METACLASS TRAITS
720
721The C<import> method generated by C<Moose::Exporter> will allow the
722user of your module to specify metaclass traits in a C<-traits>
723parameter passed as part of the import:
724
725 use Moose -traits => 'My::Meta::Trait';
726
727 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
728
729These traits will be applied to the caller's metaclass
730instance. Providing traits for an exporting class that does not create
731a metaclass for the caller is an error.
732
733=head1 AUTHOR
734
735Dave Rolsky E<lt>autarch@urth.orgE<gt>
736
737This is largely a reworking of code in Moose.pm originally written by
738Stevan Little and others.
739
740=head1 COPYRIGHT AND LICENSE
741
2840a3b2 742Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 743
744L<http://www.iinteractive.com>
745
746This library is free software; you can redistribute it and/or modify
747it under the same terms as Perl itself.
748
749=cut