++ed by:
1 non-PAUSE user
Author image Hoe-Kit Chew
and 1 contributors


Function::Runner - Define functions at a higher level and run them


  use Function::Runner;

  # Hello World
  sub greet {
      print "Hello ". ($_[0] || 'World') ."\n";
      return ('ok',$_[0]);

  my $defn = {                              # Definition is just a hashref
    '/hello' => '&greet'                    #   The /hello step,
  };                                        #     calls the &greet function

  my $fn = Function::Runner->new($defn);    # Create a greeter
  $fn->run('/hello','Flash');               # Hello Flash

  my $switch = {                            # Define a switch
    '/checkSwitch' => {
        'run'  => '&checkSwitch',           # Check the switch
        ':on'  => '&bye',                   #   If it's on, leave
        ':off' => '/turnOn',                #   If it's off, turn it on
    '/turnOn'  => {                         # Turn on the switch
        'run'  => '&greet',                 #   Greet the caller
        ':ok' => '/turnOff',                #   Then turn off the switch
    '/turnOff' => '&bye',                   # Turn off the switch and leave
  sub bye {
    print "Bye ". ($_[0] || 'World') ."\n";
    return ('ok',$_[0]);
  sub checkSwitch { return @_ }

  $fn = Function::Runner->new($switch);     # Create a switch
  $fn->run('/checkSwitch', 'on', 'Flash');  # Bye Flash

  $fn->run('/checkSwitch', 'off', 'Hulk');  # Hello Hulk
                                            # Bye Hulk

  say join ' ', @$_ for @{$fn->steps};      # List steps, function and result
                                            #   /checkSwitch &checkSwitch :off
                                            #   /turnOn &greet :ok


Function::Runner provides a way to define the steps of a function and the logical flow between the steps using just hashrefs. The user then implements the steps that need to be called. The function runner will then run the function.

This module is handy for functions that are naturally composed of many hierarchical steps and flows differently depending on the results of those steps. The function definition helps to clarify the steps and flow at a higher level.

A function definition (funcdef) is composed of three (3) constructs: steps, functions and results. Each construct is a string with a different character prefix to indicate the kind of construct:

    /a_step         # Steps are prefixed with /, like directories

    &a_function     # Functions prefixed with &, like Perl

    :some_result    # Results prefixed with :

The keys of the funcdef hashref is always a step. The value of the funcdef hashref is the step definition (stepdef) defines how that step is to be executed.

A stepdef can be just a function if no further steps follow. For example:

    { '/hello' => '&greet' }

A stepdef can also be a hashref that defines the function to run and the next step to take depending on the results of that function run. For example:

    '/checkSwitch' => {
        'run'  => '&checkSwitch',           # Check the switch
        ':on'  => '&bye',                   #   If it's on, leave
        ':off' => '/turnOn',                #   If it's off, turn it on

The next step can either be a function:

    ':on'  => '&bye'            # On "on" result, call the &bye function

or it can be another step:

    ':off' => '/turnOn'         # On "off" result, run the /turnOn step



The run() method runs the given $step, checks the results, looks up the function definition to determine the next step to run an calls that until there is nothing left to be done at which point it will return the result of the last function that was called.

Along the way it tracks how deep it is within the function definition. Each step that was ran and the corresponding result is stored in an array.


The steps() method returns the steps that ran for that function.


Steps and Functions with the form Verb + Object is rather pleasing to read. For example:



Results with the form Object + State or Object + Adjective is also rather pleasing to read. For example:



Taken together, the step and it's results end up reading like this:

    /find_stalled_workers :not_found


Defining a function in terms of steps, functions and results has several nice properties.

The valid return values from each function is clearly spelled out.

Having a funcdef makes it easier rearrange the flow of steps within that function or add an additional step in the function's processing.

It is possible to directly call the steps in a function definition.

It is possible to analyze the funcdef hashref to create a reverse dependency graph so that when a function is about to be changed, find all it's dependents.

All in all, it is a rather nice way to design these kinds of hierarchical, multi-step functions where the flow depends on the results of prior steps.


Hoe Kit CHEW <hoekit@gmail.com>


Copyright 2021- Hoe Kit CHEW


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