App-RoboBot

 view release on metacpan or  search on metacpan

lib/App/RoboBot/Macro.pm  view on Meta::CPAN

package App::RoboBot::Macro;
$App::RoboBot::Macro::VERSION = '4.004';
use v5.20;

use namespace::autoclean;

use Moose;
use MooseX::ClassAttribute;
use MooseX::SetOnce;

use App::RoboBot::Nick;
use App::RoboBot::Parser;

use Clone qw( clone );
use Data::Dumper;
use DateTime;
use DateTime::Format::Pg;
use JSON;
use Scalar::Util qw( blessed );

has 'bot' => (
    is       => 'ro',
    isa      => 'App::RoboBot',
    required => 1,
);

has 'id' => (
    is        => 'rw',
    isa       => 'Num',
    traits    => [qw( SetOnce )],
    predicate => 'has_id',
);

has 'network' => (
    is       => 'rw',
    isa      => 'App::RoboBot::Network',
    required => 1,
);

has 'name' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'arguments' => (
    is       => 'rw',
    isa      => 'HashRef',
    default  => sub { { has_optional => 0, positional => [], keyed => {}, rest => undef } },
    required => 1,
);

has 'definition' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'definer' => (
    is        => 'rw',
    isa       => 'App::RoboBot::Nick',
    predicate => 'has_definer',
);

has 'timestamp' => (
    is       => 'rw',
    isa      => 'DateTime',
    traits   => [qw( SetOnce )],
    default  => sub { DateTime->now() },
    required => 1,
);

has 'is_locked' => (
    is      => 'rw',
    isa     => 'Bool',
    default => 0,
);

has 'valid' => (
    is     => 'ro',
    isa    => 'Bool',
    writer => '_set_valid',
);

has 'error' => (
    is     => 'ro',
    isa    => 'Str',
    writer => '_set_error',
);

has 'expression' => (
    is     => 'ro',
    isa    => 'Object',
    writer => '_set_expression',
);

class_has 'log' => (
    is        => 'rw',
    predicate => 'has_logger',
);

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

    $self->log($self->bot->logger('core.macro')) unless $self->has_logger;

    $self->log->debug(sprintf('Creating new macro object for %s on network %s.', $self->name, $self->network->name));

    $self->_generate_expression($self->definition) if defined $self->definition;

    $self->log->debug(sprintf('Macro expression generated from definition for %s.', $self->name));
}

around 'definition' => sub {
    my $orig = shift;
    my $self = shift;

    return $self->$orig() unless @_;

    my $def = shift;

    $self->log->debug(sprintf('Macro definition updating for %s on network %s.', $self->name, $self->network->name));

    $self->_generate_expression($def);
    return $self->$orig($def);
};

sub _generate_expression {
    my ($self, $def) = @_;

lib/App/RoboBot/Macro.pm  view on Meta::CPAN


        $self->_set_expression([]);
        return;
    }

    $self->log->debug('Creating expression parser.');

    my $parser = App::RoboBot::Parser->new( bot => $self->bot );
    my $expr = $parser->parse($def);

    $self->log->debug('Macro definition body parsed.');

    unless (defined $expr && blessed($expr) =~ m{^App::RoboBot::Type}) {
        $self->log->debug('Parse results yielded invalid expression. Marking macro as invalid.');

        $self->_set_valid(0);
        $self->_set_error("Macro definition body must be a valid expression or list.");
        return;
    }

    $self->log->debug('Valid expression generated. Marking macro valid and setting internal expression.');

    $self->_set_valid(1);
    $self->_set_expression($expr);
};

sub load_all {
    my ($class, $bot) = @_;

    my $logger = $bot->logger('core.macro');

    $logger->debug('Macro load_all() request.');

    my $res = $bot->config->db->do(q{
        select m.macro_id, m.network_id, m.name, m.arguments, m.definition,
            n.name as nick, m.defined_at, m.is_locked
        from macros m
            join nicks n on (n.id = m.defined_by)
    });

    return unless $res;

    my %macros;

    while ($res->next) {
        my $network = $bot->network_by_id($res->{'network_id'});
        next unless defined $network;

        $logger->debug(sprintf('Loading macro %s for network %s.', $res->{'name'}, $network->name));

        $macros{$network->id} = {} unless exists $macros{$network->id};

        $macros{$network->id}{$res->{'name'}} = $class->new(
            bot        => $bot,
            id         => $res->{'macro_id'},
            network    => $network,
            name       => $res->{'name'},
            arguments  => decode_json($res->{'arguments'}),
            definition => $res->{'definition'},
            definer    => App::RoboBot::Nick->new( config => $bot->config, name => $res->{'nick'} ),
            timestamp  => DateTime::Format::Pg->parse_datetime($res->{'defined_at'}),
            is_locked  => $res->{'is_locked'},
        );
    }

    $logger->debug('All macros loaded. Returning collection.');

    return %macros;
}

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

    $self->log->debug(sprintf('Save request for macro %s on network %s.', $self->name, $self->network->name));

    my $res;

    if ($self->has_id) {
        $self->log->debug(sprintf('Macro %s already has ID (%d). Updating existing record.', $self->name, $self->id));

        $res = $self->bot->config->db->do(q{
            update macros set ??? where macro_id = ?
        }, {
            name       => $self->name,
            arguments  => encode_json($self->arguments),
            definition => $self->definition,
            is_locked  => $self->is_locked,
        }, $self->id);

        return 1 if $res;
    } else {
        $self->log->debug(sprintf('Macro %s does not have ID. Creating new record.', $self->name));

        unless ($self->has_definer) {
            $self->log->error(sprintf('Attempted to save macro %s on network %s without a definer attribute.', $self->name, $self->network->name));
            return 0;
        }

        $res = $self->bot->config->db->do(q{
            insert into macros ??? returning macro_id
        }, {
            name       => $self->name,
            network_id => $self->network->id,
            arguments  => encode_json($self->arguments),
            definition => $self->definition,
            defined_by => $self->definer->id,
            defined_at => $self->timestamp,
            is_locked  => $self->is_locked,
        });

        if ($res && $res->next) {
            $self->log->debug(sprintf('New macro record created for %s on network %s (ID %d).', $self->name, $self->network->name, $res->{'macro_id'}));

            $self->id($res->{'macro_id'});
            return 1;
        }
    }

    $self->log->error(sprintf('Save for macro %s on network %s failed.', $self->name, $self->network->name));
    return 0;
}



( run in 0.563 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )