Lingua-Awkwords

 view release on metacpan or  search on metacpan

lib/Lingua/Awkwords/Subpattern.pm  view on Meta::CPAN

);

has pattern => (
    is      => 'rw',
    trigger => sub {
        my ($self, $pat) = @_;
        die "subpattern $pat does not exist" unless exists $patterns{$pat};
        $self->_set_target($patterns{$pat});
    },
);
has target => (is => 'rwp',);

########################################################################
#
# METHODS

sub get_patterns {
    return %patterns;
}

sub is_pattern {
    my (undef, $pat) = @_;
    return exists $patterns{$pat};
}

sub render {
    my ($self) = @_;

    my $ret;
    my $target = $self->target;
    my $type   = ref $target;

    # this complication allows for subpatterns to point at other parse
    # trees instead of just simple terminal strings (yes, you could
    # create loops where a ->render points to itself (don't do that))
    #
    # NOTE walk sub must be kept in sync with this logic
    if (!$type) {
        $ret = $target;
    } else {
        if ($type eq 'ARRAY') {
            # do not need Math::Random::Discrete here as the weights are
            # always equal; for weighted instead write that unit out
            # manually via [a*2/e/i/o/u] or such
            $ret = @{$target}[ rand @$target ] // '';
        } else {
            $ret = $target->render;
        }
    }
    return $ret;
}

sub set_patterns {
    my $class_or_self = shift;
    # TODO error checking here may be beneficial if callers are in the
    # habit of passing in data that blows up on ->render or ->walk
    %patterns = (%patterns, @_);
    return $class_or_self;
}

sub update_pattern {
    my $class_or_self = shift;
    my $pattern       = shift;

    # TODO more error checking here may be beneficial if callers are in
    # the habit of passing in data that blows up on ->render
    croak "update needs a pattern and a list of values\n" unless @_;
    croak "value must be defined" if !defined $_[0];

    # NOTE arrayref as single argument is saved without making a copy of
    # the contents; this will allow the caller to potentially change
    # that ref and thus influence what is stored in patterns after this
    # update_pattern call
    $patterns{$pattern} = @_ == 1 ? $_[0] : [@_];

    return $class_or_self;
}

sub walk {
    my ($self, $callback) = @_;

    $callback->($self);

    my $target = $self->target;
    my $type   = ref $target;

    # NOTE this logic must be kept in sync with render sub
    if ($type and $type ne 'ARRAY') {
        $target->walk($callback);
    }
    return;
}

1;
__END__

=head1 NAME

Lingua::Awkwords::Subpattern - implements named subpatterns

=head1 SYNOPSIS

  use feature qw(say);
  use Lingua::Awkwords;
  use Lingua::Awkwords::Subpattern;

  # pick-one-of-these patterns (equal weights)
  Lingua::Awkwords::Subpattern->set_patterns(
      C => [qw/p t k s m n/],
      N => [qw/m n/],
      V => [qw/a i u/],
  );

  my $triphthong = Lingua::Awkwords->new( pattern => q{ VVV } );
  say $triphthong->render;

  # patterns can also point to parse trees
  Lingua::Awkwords::Subpattern->update_pattern(
      T => $triphthong
  );



( run in 2.592 seconds using v1.01-cache-2.11-cpan-98e64b0badf )