POE::Lego, by billn

Yeah, I'm a big fan of Legos. When I was a kid, I never got a complete set. I had /some/, mixed with pieces I got from sharing my toys with cousins, sibling, or friends. The write-up that follows is concrete evidence that building with modular components is now deeply ingrained, and I tend to view Perl modules in the same context.

The basic premise of this concept hangs completely on the fact that POE states/events can be added and removed during execution. The rest is simple architecture and code handling, coupled with eval. As Rocco comments, the whole thing is deceptively simple.

Note: I stole some chunks of the code below from the IRC component modules, because they're fabulous.

#!/usr/bin/perl

use strict;
use warnings;
use POE;

POE::Session->create(
  package_states => ['main' => [qw(_default _start _reload)],]);

$poe_kernel->run();
exit 0;

sub _start {
  my ($kernel, $session) = @_[KERNEL, SESSION];

  $kernel->yield('_reload');    # Load event code
  $kernel->sig(HUP => 'sig_hup')
    ;    # Hitch sig HUP to the wagon, call a code reload whenever we get one
  $kernel->yield('init');    # Call externally loaded init for dynamic setup
}

sub _reload {
  my ($kernel, $session) = @_[KERNEL, SESSION];

  foreach my $subroutine (<events/*>) {
    my $code;
    chomp($subroutine);
    open(my $fh_in, '<', $subroutine);
    while (<$fh_in>) { $code .= $_ }
    close($fh_in);

    $subroutine =~ s/^events\///;

    if (my $new_state =
      eval q(sub { my ($kernel, $heap) = @_[KERNEL, HEAP]; ) . $code . q(})) {
      $kernel->state($subroutine, $new_state);
    }
  }
}

sub _default {
  my ($kernel, $session) = @_[KERNEL, SESSION];

  my ($event, $args) = @_[ARG0 .. $#_];
  my @output = ("$event: ");

  foreach my $arg (@$args) {
    if (ref($arg) eq 'ARRAY') {
      push(@output, "[" . join(" ,", @$arg) . "]");
    }
    else { push(@output, "'$arg'"); }
  }
  print STDOUT 'Default: ' . join ' ', @output, " (session $session)\n";
  return 0;
}

And that's it! At least, that's the basic premise. Some things to keep in mind:

-- billn <billn at billn.net>