File Coverage

blib/lib/Text/Indent/Tiny.pm
Criterion Covered Total %
statement 50 55 90.9
branch 11 20 55.0
condition 12 19 63.1
subroutine 16 18 88.8
pod 6 8 75.0
total 95 120 79.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Text::Indent::Tiny - tiny and flexible indentation across modules
4              
5             =head1 VERSION
6              
7             This module version is 0.1.1.
8              
9             =head1 SYNOPSIS
10              
11             Simple usage:
12              
13             use Text::Indent::Tiny;
14              
15             my $indent = Text::Indent::Tiny->new(
16             eol => 1,
17             size => 1,
18             level => 2,
19             );
20              
21             Cross-module usage:
22              
23             use Text::Indent::Tiny (
24             eol => 1,
25             size => 1,
26             level => 2,
27             );
28              
29             my $indent = Text::Indent::Tiny->instance;
30              
31             Another and more realistic way of the cross-module usage:
32              
33             use Text::Indent::Tiny;
34              
35             my $indent = Text::Indent::Tiny->instance(
36             eol => 1,
37             size => 1,
38             level => 2,
39             );
40              
41             =head1 DESCRIPTION
42              
43             The module is designed to be used for printing indentation in the simplest way as much as possible. It provides methods for turning on/off indentation and output using the current indentation.
44              
45             The module design was invented during discussion on the PerlMonks board at L. Monks suggested to name the methods for increasing and decreasing indents in the POD-like style. Also they inspired to C.
46              
47             =head1 INSTANTIATING
48              
49             =head2 Constructor B
50              
51             The constructor is used for creating the indentaion object. If you need to use indentaion in one style across modules, initialize the indent object in the main program and instatiate it in other modules with the method B.
52              
53             To construct a new B object, invoke the B method passing the following options as a hash:
54              
55             =over 4
56              
57             =item B
58              
59             The initial indentation level. Defaults to C<0> (meaning no indent). The specified initial level means the left edge which cannot be crossed at all. So any any indents will be estimated from this level.
60              
61             =item B
62              
63             The number of indent spaces used for each level of indentation. If not specified, the B<$Text::Indent::Tiny::DefaultSize> is used.
64              
65             =item B
66              
67             The flag to use C as indent.
68              
69             =item B
70              
71             The arbitrary text that is assumed to be indentation.
72              
73             =item B
74              
75             If specified, tell the B method to add automatically new lines to the input arguments.
76              
77             =back
78              
79             The options B, B and B have impact on the same stuff. When specified, B has the highest priority. If B is specified, it cancels B and any other characters in favor of C.
80              
81             =head2 Singleton B
82              
83             This method returns the current object instance or create a new one by calling the constructor. In fact, it implements a singleton restricting the only instance across a program and its modules. It allows the same set of arguments as the constructor.
84              
85             =head1 METHODS
86              
87             The following methods are used for handling with indents: increasing, decreasing, resetting them and applying indents to strings.
88              
89             There are two naming styles. The first one is a POD-like style, the second one is more usual.
90              
91             Calling the methods in a void context is applied to the instance itself. If the methods are invoked in the scalar context, a new instance is created in this context and changes are applied for this instance only. See for details the Examples 1 and 2.
92              
93             =head2 B, B
94              
95             Increase the indentation by one or more levels. Defaults to C<1>.
96              
97             =head2 B, B
98              
99             Decrease the indentation by one or more levels. Defaults to C<1>.
100              
101             =head2 B, B
102              
103             Reset all indentations to the initial level (as it has been set in the cunstructor).
104              
105             =head2 B
106              
107             This method returns all arguments indented. Accordingly the B option and the configured C<$\> variable it appends all but last arguments with new line.
108              
109             =head2 Example
110              
111             use Text::Indent::Tiny;
112             my $indent = Text::Indent::Tiny->new;
113              
114             # Let's use newline per each item
115             $\ = "\n";
116              
117             # No indent
118             print $indent->item("Poem begins");
119              
120             # Indent each line with 4 spaces (by default)
121             $indent->over;
122             print $indent->item(
123             "To be or not to be",
124             "That is the question",
125             );
126             $indent->back;
127              
128             # Indent the particular line locally to 5th level (with 20 spaces)
129             print $indent->over(5)->item("William Shakespeare");
130              
131             # No indent
132             print $indent->item("Poem ends");
133              
134             =head1 VARIABLES
135              
136             =over 4
137              
138             =item B<$Text::Indent::Tiny::DefaultSpace>
139              
140             The text to be used for indentation. Defaults to one C character.
141              
142             =item B<$Text::Indent::Tiny::DefaultSize>
143              
144             The number of indent spaces used for each level of indentation. Defaults to C<4>.
145              
146             =back
147              
148             =head1 OVERLOADING
149              
150             Some one could find more convenient using the indents as objects of arithmetic operations and/or concatenated strings.
151              
152             The module overloads the following operations:
153              
154             =over 4
155              
156             =item C<"">
157              
158             Stringify the indentation.
159              
160             =item C<+>
161              
162             Increase the indentation.
163              
164             =item C<->
165              
166             Decrease the indentation.
167              
168             =item C<.>
169              
170             The same as C<< $indent->item() >>.
171              
172             =back
173              
174             =head2 Example
175              
176             So using the overloading the above example can looks more expressive:
177              
178             use Text::Indent::Tiny;
179             my $indent = Text::Indent::Tiny->new;
180              
181             # Let's use newline per each item
182             $\ = "\n";
183              
184             # No indent
185             print $indent . "Poem begins";
186              
187             # Indent each line with 4 spaces (by default)
188             print $indent + 1 . [
189             "To be or not to be",
190             "That is the question",
191             ];
192              
193             # Indent the particular line locally to 5th level (with 20 spaces)
194             print $indent + 5 . "William Shakespeare";
195              
196             # No indent
197             print $indent . "Poem ends";
198              
199             =head1 SEE ALSO
200              
201             L
202              
203             L
204              
205             L
206              
207             L
208              
209             L
210              
211             =head1 ACKNOWLEDGEMENTS
212              
213             Thanks to PerlMonks community for suggesting good ideas.
214              
215             L
216              
217             =head1 AUTHOR
218              
219             Ildar Shaimordanov, C<< >>
220              
221             =head1 LICENSE AND COPYRIGHT
222              
223             This software is Copyright (c) 2020 by Ildar Shaimordanov.
224              
225             This program is released under the following license:
226              
227             MIT License
228              
229             Copyright (c) 2017-2020 Ildar Shaimordanov
230              
231             Permission is hereby granted, free of charge, to any person obtaining a copy
232             of this software and associated documentation files (the "Software"), to deal
233             in the Software without restriction, including without limitation the rights
234             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
235             copies of the Software, and to permit persons to whom the Software is
236             furnished to do so, subject to the following conditions:
237              
238             The above copyright notice and this permission notice shall be included in all
239             copies or substantial portions of the Software.
240              
241             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
242             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
243             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
244             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
245             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
246             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
247             SOFTWARE.
248              
249             =cut
250              
251             package Text::Indent::Tiny;
252              
253 4     4   116613 use 5.004;
  4         20  
254              
255 4     4   18 use strict;
  4         7  
  4         67  
256 4     4   17 use warnings;
  4         7  
  4         109  
257              
258 4     4   18 use Carp;
  4         4  
  4         1935  
259              
260             our $VERSION = "0.1.1";
261              
262             # Default indent settings: 4 spaces per one indent
263              
264             our $DefaultSpace = " ";
265             our $DefaultSize = 4;
266              
267             # The indent that is supposed to be used across a program and modules.
268              
269             my $indent;
270              
271             # Aliases for using in more familiar kind
272              
273             *reset = \&cut;
274             *increase = \&over;
275             *decrease = \&back;
276              
277             # =========================================================================
278              
279             # Clamp a value on the edge, that is minimum.
280             # So the value can't be less than this restriction.
281              
282             sub lclamp {
283 18     18 0 32 my ( $min, $v ) = @_;
284 18 50       44 $v < $min ? $min : $v;
285             }
286              
287             # Set the valid level and evaluate the proper indentation.
288              
289             sub set_indent {
290 12     12 0 18 my $self = shift;
291 12   100     30 my $v = shift || 0;
292              
293 12 100       46 if ( defined wantarray ) {
294 6         7 $self = bless { %{ $self } }, ref $self;
  6         31  
295             }
296              
297 12         113 $self->{level} = lclamp($self->{initial}, $self->{level} + $v);
298 12         27 $self->{indent} = $self->{text} x $self->{level};
299              
300 12         30 return $self;
301             }
302              
303             # =========================================================================
304              
305             sub new {
306 3     3 1 642 my $class = shift;
307 3         8 my %p = @_;
308              
309 3         4 my $t = $DefaultSpace;
310 3         5 my $s = $DefaultSize;
311              
312 3 50 66     35 $p{text} ||= $p{tab} ? "\t" : $t x lclamp(1, $p{size} || $s);
      33        
313 3   50     13 $p{level} = lclamp(0, $p{level} || 0);
314              
315             my $self = bless {
316             text => $p{text},
317             eol => $p{eol},
318             level => $p{level},
319             initial => $p{level},
320 3         10 }, $class;
321              
322 3         9 $self->set_indent;
323              
324 3         71 return $self;
325             }
326              
327             # =========================================================================
328              
329             sub instance {
330 3 50   3 1 1030 $indent = defined $indent ? $indent : new(@_);
331             }
332              
333             # =========================================================================
334              
335             use overload (
336             '""' => sub {
337 1     1   8 shift->{indent};
338             },
339             '.' => sub {
340 4     4   299 shift->item(shift);
341             },
342             '+' => sub {
343 3     3   725 shift->over(shift);
344             },
345             '-' => sub {
346 0 0   0   0 croak "No sense to subtract indent from number" if $_[2];
347 0         0 shift->back(shift);
348             },
349 4     4   1992 );
  4         1958  
  4         68  
350              
351             # =========================================================================
352              
353             sub import {
354 6     6   694 my $pkg = shift;
355 6 100       115 $indent = $pkg->new(@_) if @_;
356             }
357              
358             # =========================================================================
359              
360             sub item {
361 10     10 1 526 my $self = shift;
362 10 50       26 @_ = @{ $_[0] } if ref $_[0] eq "ARRAY";
  0         0  
363 10 50 33     28 my $e = $self->{eol} && ! $\ ? "\n" : "";
364 10   100     49 join($e || $\ || "", map { "$self->{indent}$_" } @_) . $e;
  10         81  
365             }
366              
367             sub cut {
368 0     0 1 0 my $self = shift;
369 0         0 $self->set_indent($self->{initial} - $self->{level});
370             }
371              
372             sub over {
373 7     7 1 481 my ( $self, $v ) = @_;
374 7 50       19 $v = $v->{level} if ref $v eq __PACKAGE__;
375 7   100     33 $self->set_indent(+abs($v || 1));
376             }
377              
378             sub back {
379 2     2 1 450 my ( $self, $v ) = @_;
380 2 50       7 $v = $v->{level} if ref $v eq __PACKAGE__;
381 2   50     26 $self->set_indent(-abs($v || 1));
382             }
383              
384             1;
385              
386             # =========================================================================
387              
388             # EOF