1package Text::Outdent;
2use 5.006;
3
4$VERSION = 0.01;
5@EXPORT_OK = qw/
6    outdent
7    outdent_all
8    outdent_quote
9    expand_leading_tabs
10/;
11$EXPORT_TAGS{ALL} = \@EXPORT_OK;
12
13use strict;
14use base 'Exporter';
15
16{
17    my $indent_re = qr/^([^\S\n]*(?=\S))/m;
18    sub find_indention {
19        my ($str) = @_;
20
21        return '' if $str !~ /\S/;
22
23        $str =~ /$indent_re/g;
24        my $i = $1;
25        return '' if not length $i;
26
27        while ($str =~ /$indent_re/g) {
28            my $i2 = $1;
29            ($i) = "$i\n$i2" =~ /^(.*).*\n\1/;
30            return '' if not length $i2;
31        }
32        return $i;
33    }
34}
35
36{
37    my $indent_re = qr/^(?!$)([^\S\n]*)/m;
38    sub find_indention_all {
39        my ($str) = @_;
40
41        $str =~ /$indent_re/g;
42        my $i = $1;
43        return '' if not length $i;
44
45        while ($str =~ /$indent_re/g) {
46            my $i2 = $1;
47            ($i) = "$i\n$i2" =~ /^(.*).*\n\1/;
48            return '' if not length $i2;
49        }
50        return $i;
51    }
52}
53
54sub outdent_all {
55    my ($str) = @_;
56
57    my $indent = find_indention_all($str);
58    $str =~ s/^$indent//gm;
59
60    return $str;
61}
62
63sub outdent {
64    my ($str) = @_;
65
66    my $indent = find_indention($str);
67    $str =~ s/^$indent(?=.*?\S)//gm;
68
69    return $str;
70}
71
72# Removes any leading whitespaces uptil and including the first whitespace.
73# Removes any trailing whitespaces if they come directly after a newline.
74# (In this paragraph "whitespace" excludes newline.)
75sub heredocify {
76    my ($str) = @_;
77
78    $str =~ s/^[^\S\n]*\n//;
79    $str =~ s/^[^\S\n]+\z//m;
80
81    return $str;
82}
83
84sub outdent_quote { outdent(heredocify($_[0])) }
85
86sub expand_leading_tabs {
87    my ($tabstop, $str) = @_;
88
89    1 while $str =~ s{
90        ^ ([^\S\t\n]*?) (\t+)
91    }{
92        $1 . ' ' x ($tabstop * length($2) - length($1) % $tabstop)
93    }gemx;
94
95    return $str;
96}
97
981;
99
100__END__
101
102=head1 NAME
103
104Text::Outdent - Outdent chunks of text
105
106
107=head1 SYNOPSIS
108
109    my $foo = outdent($bar);
110
111    my $baz = outdent_quote(q{
112        this
113            is
114            a
115        string
116            that
117            is
118            indented
119        with
120            spaces
121            or
122            tab
123    });
124
125
126=head1 DESCRIPTION
127
128This module was created to make it easy to have large chunks of strings in the code. If you use a quote operator that spans over several lines or a "here-doc" and have an indention of the code you get leading whitespaces that you may or may not want. If you don't want them this module easily removes them.
129
130You can also use it for other texts that are indented.
131
132
133=head1 EXPORTED FUNCTIONS
134
135No functions are exported by default. C<:ALL> exports all.
136
137=over
138
139=item C<outdent($str)>
140
141Removes the common leading whitespaces for each line. Currently lines with only whitespaces are ignored and left untouched; treated as blank lines if you like. No tab expansion is being performed; a tab is just a whitespace character.
142
143If the indention consists of both spaces and tabs then it's a good idea to expand the tabs first, see C<&expand_leading_tabs>. If the mix of tabs and spaces is consistent, e.g. every line begins with "E<nbsp>E<nbsp>\tE<nbsp>", then that is recognized as indention.
144
145    # common leading whitespaces are removed.
146    my $str = <<'_STR_';
147        this
148            is
149            a
150        string
151            that
152            is
153            indented
154        with
155            spaces
156            or
157            tab
158    _STR_
159
160    print '* Indented: ', $str;
161    print '* Outdented: ', outdent($str);
162
163outputs
164
165    * Indented:
166        this
167            is
168            a
169        string
170            that
171            is
172            indented
173        with
174            spaces
175            or
176            tab
177
178    * Outdented:
179    this
180        is
181        a
182    string
183        that
184        is
185        indented
186    with
187        spaces
188        or
189        tab
190
191=item C<outdent_all($str)>
192
193Like C<&outdent> except it doesn't treat "whitespace lines" as blank lines.
194
195=item C<outdent_quote($str)>
196
197Like C<&outdent> but with some twists to make it smooth to use a (possibly indented) quote operator spanning over several lines in your source. The arrows (that isn't part of the code) below point out the two issues this function takes care of.
198
199    my $foo = q{       <--- newline and possible spaces
200        foo
201            bar
202            baz
203        zip
204            zap
205    };                 <--- empty line with possible spaces
206
207First, all whitespaces uptil the first newline plus the newline itself are removed. This takes care of the first issue.
208
209Second, if the string ends with a newline followed by non-newline whitespaces the non-newline whitespaces are removed. This takes care of the second issue.
210
211These fixes serve to make the quote operator's semantics equivalent to a here-docs.
212
213=item C<expand_leading_tabs($tabstop, $str)>
214
215Expands tabs that on a line only have whitespaces before them. Handy to have if you have a file with mixed tab/space indention.
216
217=back
218
219
220=head1 AUTHOR
221
222Johan Lodin <lodin@cpan.org>
223
224
225=head1 COPYRIGHT
226
227Copyright 2004-2005 Johan Lodin. All rights reserved.
228
229This library is free software; you can redistribute it and/or modify
230it under the same terms as Perl itself.
231
232
233=head1 SEE ALSO
234
235
236=cut
237