package Indent::Block;
use strict;
use warnings;
use Class::Utils qw(set_params);
use Indent::Utils qw(line_size_check string_len);
use Readonly;
# Constants.
Readonly::Scalar my $EMPTY_STR => q{};
Readonly::Scalar my $LINE_SIZE => 79;
our $VERSION = 0.08;
# Constructor.
sub new {
my ($class, @params) = @_;
my $self = bless {}, $class;
# Line size.
$self->{'line_size'} = $LINE_SIZE;
# Next indent.
$self->{'next_indent'} = "\t";
# Output.
$self->{'output_separator'} = "\n";
# Strict mode - without white space optimalization.
$self->{'strict'} = 1;
# Process params.
set_params($self, @params);
# 'line_size' check.
line_size_check($self);
# Save current piece.
$self->{'_current'} = $EMPTY_STR;
# Object.
return $self;
}
# Parses tag to indented data.
sub indent {
my ($self, $data_ar, $act_indent, $non_indent) = @_;
# Undef indent.
if (! $act_indent) {
$act_indent = $EMPTY_STR;
}
# Input data.
my @input = @{$data_ar};
# If non_indent data, than return.
if ($non_indent) {
return $act_indent.join($EMPTY_STR, @input);
}
# Indent.
my @data = ();
my ($first, $second);
$first = shift @input;
my $tmp_indent = $act_indent;
while (@input) {
$second = shift @input;
if ($self->_compare($first, $second, $tmp_indent)) {
push @data, $self->{'_current'};
$first = $second;
$second = $EMPTY_STR;
$tmp_indent = $act_indent.$self->{'next_indent'};
} else {
$first .= $second;
}
}
# Add other data to @data array.
if ($first) {
# White space optimalization.
if (! $self->{'strict'}) {
$first =~ s/^\s*//ms;
$first =~ s/\s*$//ms;
}
if ($first ne $EMPTY_STR) {
push @data, $tmp_indent.$first;
}
}
# Return as array or one line with output separator between its.
return wantarray ? @data : join($self->{'output_separator'}, @data);
}
# Compare strings with 'line_size' and save right current string.
sub _compare {
my ($self, $first, $second, $act_indent) = @_;
# Without optimalization.
if ($self->{'strict'}) {
if (length $first > 0
&& (string_len($act_indent.$first)
>= $self->{'line_size'}
|| string_len($act_indent.$first.$second)
> $self->{'line_size'})) {
$self->{'_current'} = $act_indent.$first;
return 1;
} else {
return 0;
}
# With optimalizaton.
# TODO Rewrite.
} else {
my $tmp1 = $first;
$tmp1 =~ s/^\s*//ms;
$tmp1 =~ s/\s*$//ms;
if (length $tmp1 > 0
&& string_len($act_indent.$tmp1)
>= $self->{'line_size'}) {
$self->{'_current'} = $act_indent.$tmp1;
return 1;
} else {
my $tmp2 = $first.$second;
$tmp2 =~ s/^\s*//ms;
$tmp2 =~ s/\s*$//ms;
if (length $tmp1 > 0
&& string_len($act_indent.$tmp2)
> $self->{'line_size'}) {
$self->{'_current'} = $act_indent.$tmp1;
return 1;
} else {
return 0;
}
}
}
}
1;
__END__
=pod
=encoding utf8
=head1 NAME
Indent::Block - Class for block indenting.
=head1 SYNOPSIS
use Indent::Block;
my $obj = Indent::Block->new(%parameters);
my $string = $obj->indent($data, [$act_indent, $non_indent]);
my @data = $obj->indent($data, [$act_indent, $non_indent]);
=head1 METHODS
=head2 C<new>
my $obj = Indent::Block->new(%parameters);
Constructor.
Returns instance of object.
=over 8
=item * C<line_size>
Sets indent line size value.
Default value is 'line_size' => 79.
=item * C<next_indent>
Sets next indent string.
Default value is 'next_indent' => "\t" (tabelator).
=item * C<output_separator>
Sets output separator between indented datas for string context.
Default value is 'output_separator' => "\n" (new line).
=item * C<strict>
Sets or unsets strict mode.
Unset strict mode means whitespace optimalization.
Default value is 'strict' => 1.
=back
=head2 C<indent>
my $string = $obj->indent($data, [$act_indent, $non_indent]);
or
my @data = $obj->indent($data, [$act_indent, $non_indent]);
Indent method.
- C<$data_ar> - Reference to array with strings to indent.
- C<$act_indent> - String to actual indent.
- C<$non_indent> - Flag, that says 'no-indent' for current time.
Returns string to print or array of data to print.
=head1 ERRORS
new():
From Class::Utils::set_params():
Unknown parameter '%s'.
From Indent::Utils::line_size_check():
'line_size' parameter must be a positive number.
line_size => %s
=head1 EXAMPLE
use strict;
use warnings;
use Indent::Block;
# Object.
my $i = Indent::Block->new(
'line_size' => 2,
'next_indent' => '',
);
# Print in scalar context.
print $i->indent(['text', 'text', 'text'])."\n";
# Output:
# text
# text
# text
=head1 DEPENDENCIES
L<Class::Utils>,
L<Indent::Utils>,
L<Readonly>.
=head1 SEE ALSO
=over
=item L<Indent>
Class for indent handling.
=item L<Indent::Data>
Class for data indenting.
=item L<Indent::String>
Class for text indenting.
=item L<Indent::Utils>
Utilities for Indent classes.
=item L<Indent::Word>
Class for word indenting.
=back
=head1 REPOSITORY
L<https://github.com/michal-josef-spacek/Indent>
=head1 AUTHOR
Michal Josef Špaček L<mailto:skim@cpan.org>
L<http://skim.cz>
=head1 LICENSE AND COPYRIGHT
© 2005-2021 Michal Josef Špaček
BSD 2-Clause License
=head1 VERSION
0.08
=cut