1 package PPI::Transform;
7 PPI::Transform - Abstract base class for document transformation classes
11 C<PPI::Transform> provides an API for the creation of classes and objects
12 that modify or transform PPI documents.
22 use Params::Util qw{_INSTANCE _CLASS _CODE _SCALAR0};
24 use vars qw{$VERSION};
33 #####################################################################
34 # Apply Handler Registration
39 # Yes, you can use this yourself.
40 # I'm just leaving it undocumented for now.
41 sub register_apply_handler {
43 my $handler = _CLASS(shift) or Carp::croak("Invalid PPI::Transform->register_apply_handler param");
44 my $get = _CODE(shift) or Carp::croak("Invalid PPI::Transform->register_apply_handler param");
45 my $set = _CODE(shift) or Carp::croak("Invalid PPI::Transform->register_apply_handler param");
46 if ( $HANDLER{$handler} ) {
47 Carp::croak("PPI::Transform->apply handler '$handler' already exists");
50 # Register the handler
51 $HANDLER{$handler} = [ $get, $set ];
52 unshift @ORDER, $handler;
55 # Register the default handlers
56 __PACKAGE__->register_apply_handler( 'SCALAR', \&_SCALAR_get, \&_SCALAR_set );
57 __PACKAGE__->register_apply_handler( 'PPI::Document', sub { $_[0] }, sub { 1 } );
63 #####################################################################
70 my $transform = PPI::Transform->new(
75 The C<new> constructor creates a new object for your C<PPI::Transform>
76 subclass. A default constructor is provided for you which takes no params
77 and creates a basic, empty, object.
79 If you wish to have your transform constructor take params, these B<must>
80 be in the form of a list of key/value pairs.
82 Returns a new C<PPI::Transform>-compatible object, or returns
96 The C<document> method should be implemented by each subclass, and
97 takes a single argument of a L<PPI::Document> object, modifying it
98 B<in place> as appropriate for the particular transform class.
100 That's right, this method B<will not clone> and B<should not clone>
101 the document object. If you do not want the original to be modified,
102 you need to clone it yourself before passing it in.
104 Returns the numbers of changes made to the document. If the transform
105 is unable to track the quantity (including the situation where it cannot
106 tell B<IF> it made a change) it should return 1. Returns zero if no
107 changes were made to the document, or C<undef> if an error occurs.
109 By default this error is likely to only mean that you passed in something
110 that wasn't a L<PPI::Document>, but may include additional errors
111 depending on the subclass.
117 die "$class does not implement the required ->document method";
124 The C<apply> method is used to apply the transform to something. The
125 argument must be a L<PPI::Document>, or something which can be turned
126 into a one and then be written back to again.
128 Currently, this list is limited to a C<SCALAR> reference, although a
129 handler registration process is available for you to add support for
130 additional types of object should you wish (see the source for this module).
132 Returns true if the transform was applied, false if there is an error in the
133 transform process, or may die if there is a critical error in the apply
139 my $self = _SELF(shift);
140 my $it = defined $_[0] ? shift : return undef;
142 # Try to find an apply handler
143 my $class = _SCALAR0($it) ? 'SCALAR'
144 : List::Util::first { _INSTANCE($it, $_) } @ORDER
146 my $handler = $HANDLER{$class}
147 or die("->apply handler for $class missing! Panic");
150 my $Document = _INSTANCE($handler->[0]->($it), 'PPI::Document')
151 or Carp::croak("->apply handler for $class failed to get a PPI::Document");
152 $self->document( $Document ) or return undef;
153 $handler->[1]->($it, $Document)
154 or Carp::croak("->apply handler for $class failed to save the changed document");
162 # Read from one file and write to another
163 $transform->file( 'Input.pm' => 'Output.pm' );
165 # Change a file in place
166 $transform->file( 'Change.pm' );
168 The C<file> method modifies a Perl document by filename. If passed a single
169 parameter, it modifies the file in-place. If provided a second parameter,
170 it will attempt to save the modified file to the alternative filename.
172 Returns true on success, or C<undef> on error.
177 my $self = _SELF(shift);
179 # Where do we read from and write to
180 my $input = defined $_[0] ? shift : return undef;
181 my $output = @_ ? defined $_[0] ? "$_[0]" : undef : $input or return undef;
184 my $Document = PPI::Document->new( "$input" ) or return undef;
185 $self->document( $Document ) or return undef;
186 $Document->save( $output );
193 #####################################################################
194 # Apply Hander Methods
197 PPI::Document->new( $_[0] );
202 $$it = $_[0]->serialize;
210 #####################################################################
214 return shift if ref $_[0];
215 my $self = $_[0]->new or Carp::croak(
216 "Failed to auto-instantiate new $_[0] object"
227 See the L<support section|PPI/SUPPORT> in the main module.
231 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
235 Copyright 2001 - 2009 Adam Kennedy.
237 This program is free software; you can redistribute
238 it and/or modify it under the same terms as Perl itself.
240 The full text of the license can be found in the
241 LICENSE file included with this module.