Graphics-Grid
view release on metacpan or search on metacpan
lib/Graphics/Grid/UnitArithmetic.pm view on Meta::CPAN
package Graphics::Grid::UnitArithmetic;
# ABSTRACT: Expression created from Graphics::Grid::Unit objects
use Graphics::Grid::Class;
our $VERSION = '0.0001'; # VERSION
use Scalar::Util qw(looks_like_number);
use Type::Params ();
use Types::Standard qw(Str ArrayRef Any Num);
use namespace::autoclean;
use Graphics::Grid::Util qw(points_to_cm);
use Graphics::Grid::Types qw(:all);
extends 'Forest::Tree';
use overload
"+" => 'plus',
"-" => 'minus',
"*" => 'multiply',
"fallback" => 1;
has '+node' => (
isa => (
( ArrayRef [Num] )->plus_coercions( Num, sub { [$_] } ) |
Str->where( sub { $_ =~ /^[\*\+\-]$/ } ) | Unit
),
coerce => 1,
);
has '+children' => (
isa => ArrayRef [
UnitArithmetic->plus_coercions( Any,
sub {
if ( $_->$_isa('Graphics::Grid::UnitArithmetic') ) {
return $_;
}
my $node = $_;
unless ( $_->$_isa('Graphics::Grid::Unit')
or Ref::Util::is_arrayref($node) )
{
$node = [$node];
}
return Graphics::Grid::UnitArithmetic->new( node => $node );
}
)
],
coerce => 1,
);
with qw(
Graphics::Grid::UnitLike
);
method at($idx) {
if ( $self->is_unit ) {
return __PACKAGE__->new( node => $self->node->at($idx) );
}
elsif ( $self->is_number ) {
return __PACKAGE__->new(
node => [ $self->node->[ $idx % $self->elems ] ] );
}
else {
return __PACKAGE__->new(
node => $self->node,
children => [ map { $_->at($idx) } @{ $self->children } ]
);
}
}
method elems() {
if ( $self->is_unit ) {
return $self->node->elems;
}
elsif ( $self->is_number ) {
return scalar( @{ $self->node } );
}
else {
return List::AllUtils::max( map { $_->elems } @{ $self->children } );
}
};
method is_unit() {
return $self->node->$_isa('Graphics::Grid::Unit');
}
method is_number() {
return Ref::Util::is_arrayref( $self->node );
}
method is_arithmetic() {
return !( $self->is_unit() or $self->is_number() );
}
method stringify() {
if ( $self->is_unit ) {
return $self->node->stringify;
}
elsif ( $self->is_number ) {
return join( ', ', @{ $self->node } );
}
else {
return join(
', ',
map {
my $arg0 = $self->children->[0]->at($_);
my $arg1 = $self->children->[1]->at($_);
my $format;
if ( $self->node eq '*' ) {
if ( $arg0->is_arithmetic ) {
$format = "(%s)%s%s";
}
elsif ( $arg1->is_arithmetic ) {
$format = "%s%s(%s)";
}
}
$format //= "%s%s%s";
sprintf( $format,
$arg0->stringify, $self->node, $arg1->stringify );
} ( 0 .. $self->elems - 1 )
);
}
}
method _make_operation( $op, $other, $swap = undef ) {
return __PACKAGE__->new(
node => $op,
children => ( $swap ? [ $other, $self ] : [ $self, $other ] )
);
}
method plus( UnitLike $other, $swap = undef ) {
return $self->_make_operation( '+', $other, $swap );
}
method minus( UnitLike $other, $swap = undef ) {
return $self->_make_operation( '-', $other, $swap );
}
method multiply( ( ArrayRef [Num] | Num ) $other, $swap = undef ) {
return $self->_make_operation( '*', $other, $swap );
}
__PACKAGE__->meta->make_immutable;
1;
( run in 2.299 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )