Bot-BasicBot-Pluggable-Module-MetaSyntactic

 view release on metacpan or  search on metacpan

lib/Bot/BasicBot/Pluggable/Module/MetaSyntactic.pm  view on Meta::CPAN

package Bot::BasicBot::Pluggable::Module::MetaSyntactic;
{
  $Bot::BasicBot::Pluggable::Module::MetaSyntactic::VERSION = '1.004';
}

use strict;
use warnings;
use Carp;
use Bot::BasicBot::Pluggable::Module;
use Acme::MetaSyntactic ();
use Text::Wrap;

our @ISA     = qw(Bot::BasicBot::Pluggable::Module);

my $META = Acme::MetaSyntactic->new()
    or carp "fatal: Can't create new Acme::MetaSyntactic object";

sub init {
    my $self = shift;

    $self->{meta} = {
        limit => 100,
        wrap  => 256,
    };

    $Text::Wrap::columns = $self->{meta}{wrap};
}

sub told {
    my ( $self, $mess ) = @_;
    my $bot = $self->bot();

    # we must be directly addressed
    return
        if !(   (   defined $mess->{address}
                    && $mess->{address} eq $bot->nick()
                )
                || $mess->{channel} eq 'msg'
        );

    # ignore people we ignore
    return if $bot->ignore_nick( $mess->{who} );

    # only answer to our command (which can be our name too)
    my $src = $bot->nick() eq 'meta' ? 'raw_body' : 'body';
    return if $mess->{$src} !~ /^\s*meta(.*)/i;

    # ignore the noise
    ( my $command = "$1" ) =~ s/^\W*//;

    # pick up the commands
    ( $command, my @args ) = split /\s+/, $command;
    return if !$command || !length $command;

    # it's a theme
    if ( $command =~ /^[-\w\/]+$/ ) {
        my ( $theme, $category ) = split m'/', $command, 2;
        $self->{meta}{theme}{$command} //= _load_theme($theme, $category);
        return "No such theme: $theme"
            if !$META->has_theme($theme);
        if ( $category && $self->{meta}{theme}{$command}
            ->isa('Acme::MetaSyntactic::MultiList')
            && !grep { $_ eq $category }
            $self->{meta}{theme}{$command}->categories )
        {
            delete $self->{meta}{theme}{$command};
            return "No such theme/category: $theme/$category";
        }

        # compute the list of items
        my ( $num, $re );
        for my $arg (@args) {
            if ( $arg =~ /^[0-9]+$/ ) { $num //= $arg; }
            elsif ( $arg =~ m{^/([^\/]*)/$} ) {
                $re = eval {qr/$1/}
                    or do { ( my $err = $@ ) =~ s/ at .*//s; return $err; }
            }
            else {return}    # can't parse this argument
        }

        # enforce the limit if explicitely asked for more
        $num //= 1;
        $num = $self->{meta}{limit} if $num > $self->{meta}{limit};

        my $meta  = $self->{meta}{theme}{$command};
        my @items = $meta->name( $re ? 0 : $num );
        if ($re) {    # NOTE: the extra loop is never run if $num == 0
            @items = grep /$re/, @items;
            splice @items, $num if $num && @items > $num;
            push @items, grep /$re/, $meta->name(0)
                while @items && @items < $num;
        }
        splice @items, $self->{meta}{limit}    # enforce the limit
            if @items > $self->{meta}{limit};
        return join ' ', @items;
    }

    # it's a command
    elsif ( $command eq 'themes?' ) {
        my @themes = $META->themes();
        return join ' ', scalar @themes, 'themes available:', @themes;
    }
    elsif ( $command eq 'categories?' ) {
        return if !@args;
        my $theme = shift @args;
        $self->{meta}{theme}{$theme} //= _load_theme($theme);
        return "No such theme: $theme"
            if !$META->has_theme($theme);
        return "Theme $theme does not have any categories"
            if !$self->{meta}{theme}{$theme}
                ->isa('Acme::MetaSyntactic::MultiList');
        return join ' ', "Categories for $theme:",
            sort $self->{meta}{theme}{$theme}->categories;
    }
}

sub _load_theme {



( run in 1.021 second using v1.01-cache-2.11-cpan-39bf76dae61 )