The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Method::Workflow - Dynamic/Nested Workflows that can act as methods on an object.

DESCRIPTION

In this module a workflow is a sequence of methods, possibly nested, associated with an object or class, that can be programmatically generated, chained or mixed.

Generally you declare workflow methods as small parts of a greater design. A good example of what this module attempts to achieve is Ruby's RSPEC http://rspec.info. However workflows need not be restricted to testing.

Example workflow (Method::Workflow::Case):

Each 'task' method will be run for each 'case' method

    cases example {
        my $target;
        case a { $target = "case 1" }
        case b { $target = "case 2" }
        case c { $target = "case 2" }

        action display { print "$target\n" }
        action display_cap { print uc($target) . "\n" }
    }

    run_workflow();

Prints:

    case 1
    CASE 1
    case 2
    CASE 2
    case 3
    CASE 3

SYNOPSIS

PACKAGE WORKFLOW

    package MyWorkflow;
    use strict;
    use warnings;

    use Method::Workflow;

    workflow my_workflow {
        # $self is available for free
        $self->do_thing;

        ...

        # Tasks are all run after the workflow is complete, but before it
        # returns.
        task do_later { ... }
    }

    workflow another_workflow {
        ...
        task do_later { ... }
    }

    # Creates an instance of MyWorkflow using new() if it is defined
    # Each method in the workflow is run with the instance as $self.
    # Result is a L<Method::Workflow::Result> object.

    my $result = run_workflow( $invocant || %constructor_args );

    1;

INDEPENDENT WORKFLOW

    package MyWorkflow;
    use strict;
    use warnings;

    use Method::Workflow;

    my $wf = new_workflow root {
        workflow my_workflow {
            $self->do_thing;
            ...
            task do_later { ... }
        }

        workflow another_workflow {
            ...
            task do_later { ... }
        }
    }

    my $result = $wf->run( $invocant || %constructor_args );

    1;

Or in one shot:

    package MyWorkflow;
    use strict;
    use warnings;

    use Method::Workflow;

    my $result = do_workflow root {
        workflow my_workflow {
            $self->do_thing;
            ...
            task do_later { ... }
        }

        workflow another_workflow {
            ...
            task do_later { ... }
        }
    }

    1;

API

DECLARATIVE API (EXPORTS)

workflow NAME { ... }

Add a child workflow to the current workflow or class.

task NAME { ... }

Add a task to the current workflow or class.

my $wf = new_workflow NAME { ... }

Create a new an independent workflow.

my $result = do_workflow NAME { ... }

Create and run an independent workflow.

The result will be an instance of Method::Workflow::Result.

my $result = run_workflow( $invocant || %construction_args )

Run the class root workflow. %construction_args will be passed to the constructor for the invocant class to create the invocant object. If a blessed object is the only argument than that object will be used as the invocant.

The result will be an instance of Method::Workflow::Result.

import_templates( @CLASSES, @WORKFLOW_OBJS )

Add the specified classes and workflow objects to the list of templates in the current workflow.

$wf = root_workflow()
$wf = $class->root_workflow()

Get the root workflow for the current class. Can also be used as a class method.

OO API

This covers only the methods that are useful in general. Methods that are not private, but not useful to most people will be covered in the section titled INTERNAL API

SIMPLE ACCESSORS

These are all simple get/set accessors. They all take a single value, and return the value.

$value = $wf->invocant_class( $value )

An instance of the invocant class will be constructed and provided as the first argument ($self) to the workflow mothods.

$value = $wf->error_handler( sub { ... })

Used to define a custom error handler.

$value = $wf->parallel( $value )

If set to an integer tasks will be run in that number of child processes.

NOTE Parallel tasks is still experimental and untested.

$value = $wf->random( $value )

Tasks will be run in random order if true.

$value = $wf->sorted( $value )

Tasks will be sorted by name and then run if set to true.

$value = $wf->ordered( $value )

Tasks will be run in the order they were defined (default) if this is true.

$value = $wf->name( $value )

Get/Set the name of the task.

$value = $wf->method( $value )

Get/Set the coderef that is associated with this workflow.

METHODS

$wf = $class->new(name => $name, invocant_class => __PACKAGE__, method => sub { ... })

Create a new instance of Method::Workflow.

$wf->init()

Called by new just before it returns. Useful for subclasses, currently does nothing.

$ordering = $wf->ordering()

Returns the name of the ordering that will be used, 'random', 'sorted', 'ordered', or undef if none is set.

$result = $wf->run( $invocant || %constructor_args )

Runs the workflow against a new instance of invocant_class created using %constructor_args. If a blessed object is the only argument, it will be used as the invocant.

The result will be an instance of Method::Workflow::Result.

$wf->add_item( $workflow || $task )

Add a child workflow or task to the workflow. This is primarily used by the keywords.

@list = $wf->templates()

Get a list of all the workflows this class inherits from.

$wf->push_templates( @classes, @warkflows )

Use the specified workflows or classes that have root workflows as templates. This means $wf will inherit children and tasks form the templates.

INTERNAL API

$list_ref = $wf->templates_ref( $newref )

Get/Set the arrayref that holds the list of template workflows.

@list = $wf->pull_templates()

Get the list of templates while also clearing the list.

$wf->import_templates()

Does the action of inheriting child workflows and tasks from the templates. Should be called once per run.

@list = $wf->tasks()
$list_ref = $wf->tasks_ref( $newref )
@list = $wf->pull_tasks()
$task = $wf->pop_tasks()
$task = $wf->shift_tasks()
$wf->push_tasks( @tasks )
$wf->unshift_tasks( @tasks )

These are methods for manipulating the list of tasks. The list is cleared at the end of a run. In general you should not use these directly. Use add_item() to add tasks to a workflow.

@list = $wf->children()
@classes = $wf->children_keys()
$wf->push_children( @workflows )
@list = $wf->pull_children( $class )
@list = $wf->pull_all_children()

These are methods for manipulating the list of children. The list is cleared at the end of a run. In general you should not use these directly. Use add_item() to add children to a workflow.

Some plugins may wish to make use of these to remove children of their specific class and replace them with tasks.

$wf->process_method( $invocant, $result )

Run the method associated with the workflow.

$wf->process( $invocant, $result )

Run the workflow including task sorting and template importing.

$wf->run_items( $invocant, $result, @items )

@items must contain workflow and/or task objects. Calls process() on all items.

$wf->run_items_parallel( $invocant, $result, @items )

Like run_items() except items are run in parrallel using Parallel::Runner.

$wf->run_method( $invocant )
$wf->run_method( $invocant, $method )

Runs the specified method, or the method associated with the workflow. Runs the method within an Method::Workflow::Method object so that keywords know to which workflow items should be added.

$invocant = $wf->get_invocant( $obj || %constructor_args )

Constructs a new instance of invocant_class. Alternatively if an object is provided as an argument it will be returned as-is.

$wf->run_tasks( $invocant, $result, @tasks )

Takes care of ordering the tasks and running them, possibly in parallel.

$wf->handle_errors( $result )

Errors are all handled after tasks have been run.

TEMPLATES

Any workflow or class with a root workflow can be used as a template. Essentially any workflow that uses another as a template inherits from it.

SEE ALSO

TOOLS

Exodist::Util

This module provides a huge collection of utilites used to create Method::Workflow.

Method::Workflow::Subclass

Any extension should make use of this to provide a keyword.

Method::Workflow::Result

All workflow results are returned in a Method::Workflow::Result object.

Method::Workflow::Method

A special method that is blessed and associated with a workflow so that it can be easily found in the stack.

EXTENSIONS

Method::Workflow::SPEC

An implementation of Ruby's RSPEC.

Method::Workflow::Case

Run multiple actions in multiple scenarios.

FENNEC PROJECT

This module is part of the Fennec project. See Fennec for more details. Fennec is a project to develop an extensible and powerful testing framework. Together the tools that make up the Fennec framework provide a potent testing environment.

The tools provided by Fennec are also useful on their own. Sometimes a tool created for Fennec is useful outside the greater framework. Such tools are turned into their own projects. This is one such project.

Fennec - The core framework

The primary Fennec project that ties them all together.

AUTHORS

Chad Granum exodist7@gmail.com

COPYRIGHT

Copyright (C) 2010 Chad Granum

Method-Workflow is free software; Standard Perl license.

Method-Workflow is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.