Allow -compatible for CMOP back-compat & add docs
[gitmo/Package-DeprecationManager.git] / lib / Package / DeprecationManager.pm
CommitLineData
dc4fc8c7 1package Package::DeprecationManager;
2
3use strict;
4use warnings;
5
6use Carp qw( croak );
7use Params::Util qw( _HASH );
8use Sub::Install;
9
10sub import {
11 shift;
12 my %args = @_;
13
14 croak
15 'You must provide a hash reference -deprecations parameter when importing Package::DeprecationManager'
16 unless $args{-deprecations} && _HASH( $args{-deprecations} );
17
18 my %registry;
19
20 my $import = _build_import( \%registry );
21 my $warn = _build_warn( \%registry, $args{-deprecations} );
22
23 my $caller = caller();
24
25 Sub::Install::install_sub(
26 {
27 code => $import,
28 into => $caller,
29 as => 'import',
30 }
31 );
32
33 Sub::Install::install_sub(
34 {
35 code => $warn,
36 into => $caller,
37 as => 'deprecated',
38 }
39 );
40
41 return;
42}
43
44sub _build_import {
45 my $registry = shift;
46
47 return sub {
48 my $class = shift;
49 my %args = @_;
50
dee597ea 51 $args{-api_version} ||= delete $args{-compatible};
52
dc4fc8c7 53 $registry->{ caller() } = $args{-api_version}
54 if $args{-api_version};
55
56 return;
57 };
58}
59
60sub _build_warn {
61 my $registry = shift;
62 my $deprecated_at = shift;
63
64 my %warned;
65
66 return sub {
67 my ( $package, undef, undef, $sub ) = caller(1);
68
69 my $compat_version = $registry->{$package};
70
71 my $deprecated_at = $deprecated_at->{$sub};
72
73 return
74 if defined $compat_version
75 && defined $deprecated_at
76 && $compat_version lt $deprecated_at;
77
78 return if $warned{$package}{$sub};
79
80 if ( ! @_ ) {
81 my $msg = "$sub has been deprecated";
82 $msg .= " since version $deprecated_at"
83 if defined $deprecated_at;
84
85 @_ = $msg;
86 }
87
88 $warned{$package}{$sub} = 1;
89
90 goto &Carp::cluck;
91 };
92}
93
941;
95
96# ABSTRACT: Manage deprecation warnings for your distribution
97
98__END__
99
100=pod
101
102=head1 SYNOPSIS
103
dee597ea 104 package My::Class;
105
106 use Package::DeprecationManager
107 -deprecations => {
108 'My::Class::foo' => '0.02',
109 'My::Class::bar' => '0.05',
110 };
111
112 sub foo {
113 deprecated( 'Do not call foo!' );
114
115 ...
116 }
117
118 sub bar {
119 deprecated();
120
121 ...
122 }
123
124 package Other::Class;
125
126 use My::Class -api_version => '0.04';
127
128 My::Class->new()->foo(); # warns
129 My::Class->new()->bar(); # does not warn
130 My::Class->new()->far(); # does not warn again
dc4fc8c7 131
132=head1 DESCRIPTION
133
dee597ea 134This module allows you to manage a set of deprecations for one or more modules.
135
136When you import C<Package::DeprecationManager>, you must provide a set of
137C<-deprecations> as a hash ref. The keys are fully qualified sub/method names,
138and the values are the version when that subroutine was deprecated.
139
140As part of the import process, C<Package::DeprecationManager> will export two
141subroutines into its caller. It proves an C<import()> sub for the caller and a
142C<deprecated()> sub.
143
144The C<import()> sub allows callers of I<your> class to specify an C<-api_version>
145parameter. If this is supplied, then deprecation warnings are only issued for
146deprecations for api versions earlier than the one specified.
147
148You must call C<deprecated()> sub in each deprecated subroutine. When called,
149it will issue a warning using C<Carp::cluck()>. If you do not pass an explicit
150warning message, one will be generated for you.
151
152Deprecation warnings are only issued once for a given package, regardless of
153how many times the deprecated sub/method is called.
154
dc4fc8c7 155=cut