MPGA
====

MPGA - Make Perl Great Again - a module that makes it easy to write 
programs in Perl using a concept similar to "Flow-Driven Development".

https://github.com/nni7/MPGA

## Concept

A "flow" is simply an array reference containing a mix of data (arguments) 
and code references (functions). These elements are sequentially processed 
from left to right.

With this module, you can structure your logic like this:

```perl
use MPGA;

flow([
  'arg1', 'arg2', \&fun1,
  100, \&fun2
]);
```

## The Function Signature

Each function in the flow must expect four arguments:

```perl
sub fun1 : MPGAargsNum(2) {
    my ($self, $args, $flow, $ctx) = @_;
    
    # $self - reference to this function itself
    # $args - array ref of arguments passed to this function
    # $flow - array ref of the remaining flow (can be modified)
    # $ctx  - optional context object shared across the flow
    
    my ($val1, $val2) = @$args;
    return;
}
```

## The `:MPGAargsNum(N)` Attribute

The `:MPGAargsNum(N)` attribute explicitly defines how many arguments your 
function consumes from the flow. MPGA will automatically extract the `N` 
arguments immediately preceding the function.

Any arguments in the flow that appeared *before* those `N` arguments are 
considered **transit arguments**. They are safely preserved and 
automatically pushed back into the flow to be consumed by subsequent 
functions.

*(Note: Older code without this attribute receives all preceding arguments 
and must manage them manually. This backward compatibility is fully 
preserved).*

## Return Values

Functions can return values to inject new data or functions into the 
beginning of the remaining flow:

- **Array reference `[...]`**: Elements are unpacked and prepended to the 
  flow.
- **Hash reference `{...}`** or **Scalar**: Prepended to the flow as a 
  single element.
- **`undef`** (or empty `return;`): The flow remains unchanged.

*Order of insertion:* 
If there are transit arguments, they are placed in the flow *before* your 
function's result.
Final order: 
`[ ... transit args ..., ... function result ..., ... rest of the flow ... ]`

## Shared Context

If you need to share state across multiple functions, use `flow_ctx()`. 
The first element of the array is treated as a shared context object 
(e.g., a hash ref) and is passed to all functions as the 4th argument.

```perl
my $ctx = { counter => 0 };
flow_ctx([
    $ctx,
    \&step_one,
    \&step_two
]);
```

## Execution Limits

To protect against infinite loops (e.g., a function continuously returning 
itself into the flow), `flow()` accepts a step limit as the 3rd argument 
(0 = unlimited):

```perl
flow($flow_array, $ctx, 100); # Stops after 100 steps
```

## Debugging and Tracing

The `MPGA::Trace` module provides decorators to monitor flow execution in 
real-time, hooking into execution before and after every function.

```perl
use MPGA::Trace;

my $tracer = sub {
    my ($msg, $args, $flow) = @_;
    print "$msg | Flow size: " . scalar(@$flow) . "\n";
};

# Standard trace
flow_trace($flow_array, $ctx, $max_steps, $tracer);

# Context trace
flow_ctx_trace($flow_array, $tracer);
```

## Installation

To install this module type the following:

   perl Makefile.PL
   make
   make test
   make install

## Dependencies

This module requires NO non-core modules or libraries. It uses standard 
core modules like `Attribute::Handlers` and `Sub::Util`.

## Copyright and License

Copyright (C) 1997-2026 by Nikolay Neustroev (NN).

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
