POE::F...ckable(3pm)

πŸ’… POE::Filter::Stackable β€” bestie edition ✨

okay so we're reading from the User Contributed Perl Documentation, manual section 3pm, and the star of the show is POE::Filter::Stackable 🫢 pull up a chair, get comfy, this one's actually so good.


🌸 NAME 🌸

POE::Filter::Stackable β€” combine multiple POE::Filter objects 🧚 no cap, that's literally the whole job.


πŸŽ€ SYNOPSIS πŸŽ€

here's the vibe, in code, exactly as it is:

#!perl

use POE qw(
  Wheel::FollowTail
  Filter::Line Filter::Grep Filter::Stackable
);

POE::Session->create(
  inline_states => {
    _start => sub {
      my $parse_input_as_lines = POE::Filter::Line->new();

      my $select_sudo_log_lines = POE::Filter::Grep->new(
        Put => sub { 1 },
        Get => sub {
          my $input = shift;
          return $input =~ /sudo\[\d+\]/i;
        },
      );

      my $filter_stack = POE::Filter::Stackable->new(
        Filters => [
          $parse_input_as_lines, # first on get, last on put
          $select_sudo_log_lines, # first on put, last on get
        ]
      );

      $_[HEAP]{tailor} = POE::Wheel::FollowTail->new(
        Filename => "/var/log/system.log",
        InputEvent => "got_log_line",
        Filter => $filter_stack,
      );
    },
    got_log_line => sub {
      print "Log: $_[ARG0]\n";
    }
  }
);

POE::Kernel->run();
exit;

✨ DESCRIPTION ✨

so POE::Filter::Stackable takes a bunch of filters and glues them together so they act like one single filter. it's giving ✨illusion of unity✨. all the usual POE::Filter methods still work like normal, but secretly β€” lowkey behind the scenes β€” your data gets passed through all the stacked filters before it comes back to you. and the best part? POE::Wheel objects and stand-alone programs need zero modifications to work with a filter stack. they don't even know. iconic behavior honestly πŸ’…

in the SYNOPSIS up there, POE::Filter::Line and POE::Filter::Grep get combined into one filter that only returns a particular kind of line. and that's highkey more efficient than filtering lines in application space, because fewer events may need to be dispatched and handled. ate. πŸ”₯

internally, the filters are stored in an array. very demure, very mindful.

here's the tea on how data actually flows:

  • data added by get_one_start() flows through the filter array in increasing index order. filter #0 gets first crack at it, then filter #1, and so on down the line.
  • the get_one() call returns an item after it has passed through the last filter. so it's been through the whole gauntlet, bestie.
  • put() goes the other way β€” it passes data through the filters in descending index order. data goes through the filter with the highest index first, and put() returns the results after the data has passed through filter #0.

πŸ‘‘ PUBLIC FILTER METHODS πŸ‘‘

besides all the usual POE::Filter methods, POE::Filter::Stackable also supports the following. yes queen, there's more πŸŽ€

πŸ¦‹ new πŸ¦‹

by default, new() creates an empty filter stack that behaves like POE::Filter::Stream. it may also be given optional parameters to initialize the stack with an array of filters. slay.

my $sudo_lines = POE::Filter::Stackable->new(
  Filters => [
    POE::Filter::Line->new(),
    POE::Filter::Grep->new(
      Put => sub { 1 }, # put all items
      Get => sub { shift() =~ /sudo\[\d+\]/i },
    ),
  ]
);

πŸ“ pop πŸ“

behaves like Perl's built-in pop() for the filter stack. the highest-indexed filter is removed from the stack and returned. πŸ’€ heads up though β€” any data remaining in that filter's input buffer is lost. but it's fine, it's fine, an application may always call "get_pending" in POE::Filter on the returned filter to go get it back.

my $last_filter = $stackable->pop();
my $last_buffer = $last_filter->get_pending();

🌈 shift 🌈

behaves like Perl's built-in shift() for the filter stack. the 0th filter is removed from the stack and returned. any data remaining in that filter's input buffer gets passed to the new head of the stack β€” or it is lost if the stack becomes empty 😭. an application may also call "get_pending" in POE::Filter on the returned filter to examine the filter's input buffer.

my $first_filter = $stackable->shift();
my $first_buffer = $first_filter->get_pending();

πŸ’– push FILTER[, FILTER] πŸ’–

push() adds one or more new *FILTER*s to the end of the stack. the newly pushed *FILTER*s will process input last, and they will handle output first. okay so the ordering here is the whole point, don't skip it:

# Reverse data read through the stack.
# rot13 encode data sent through the stack.
$stackable->push(
  POE::Filter::Map->(
    Get => sub { return scalar reverse shift() },
    Put => sub { local $_ = shift(); tr[a-zA-Z][n-za-mN-ZA-M]; $_ },
  )
);

🧚 unshift FILTER[, FILTER] 🧚

unshift() adds one or more new *FILTER*s to the beginning of the stack. the newly unshifted *FILTER*s will process input first, and they will handle output last. it's the mirror image of push(), and yes she's serving symmetry πŸ’…

🌸 filters 🌸

filters() returns a list of the filters inside the Stackable filter, in the stack's native order.

calling "$filter_stack->filters()" in the SYNOPSIS would return a list of two filter objects:

POE::Filter::Line=ARRAY(0x8b5ee0)
POE::Filter::Grep=ARRAY(0x8b5f7c)

⭐ filter_types ⭐

filter_types() returns a list of class names for each filter in the stack, in the stack's native order.

calling "$filter_stack->filter_types()" in the SYNOPSIS would return a list of two class names:

POE::FIlter::Line
POE::Filter::Grep

it could easily be replaced by:

my @filter_types = map { ref } $filter_stack->filters;

πŸ”₯ SEE ALSO πŸ”₯

  • POE::Filter for more information about filters in general. the lore, if you will.
  • specific filters, amongst which are: POE::Filter::Block, POE::Filter::Grep, POE::Filter::HTTPD, POE::Filter::Line, POE::Filter::Map, POE::Filter::RecordBlock, POE::Filter::Reference, POE::Filter::Stream

πŸ™ˆ BUGS πŸ™ˆ

none currently known. we're flawless, your honor. πŸ’…


πŸ’œ AUTHORS & COPYRIGHTS πŸ’œ

the Stackable filter was contributed by Dieter Pearcey. documentation provided by Rocco Caputo. thank you legends 🫢

please see the POE manpage for more information about authors and contributors.


okay that's the whole page bestie, you're officially stacked and slaying πŸ’– this was perl v5.34.0, dated 2022-03-25, and it's the POE::F...ckable(3pm) page β€” go forth and stack responsibly βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from