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

NAME

Class::AbstractLogic - Handling Logic Abstractions

SYNOPSIS

  # the logic class definition
  package My::Logic::Foo;
  use Class::AbstractLogic-base;

  # a logic action
  action 'add',
   needs [qw(a b)],
  verify { a => sub { /^\d+$/ }, b => sub { /^\d+$/ } },
     sub { $_{a} + $_{b} };

  1;
  ...

  # logic module manager creation
  use Class::AbstractLogic;
  my $calm = Class::AbstractLogic::Manager->new;

  # loading a logic class
  $calm->load_logic(Foo => 'My::Logic::Foo');

  # requesting a result from a logic method
  my $result = $calm->logic('Foo')->add(a => 11, b => 12);

  # $result will be false if an exception was caught
  if ($result) {
    print 'result was ' . $result->value . "\n";
  }
  else {
    print 'exception raised: ' . $result->key . "\n";
    print 'error message: ' . $result->error . "\n";
  }

DESCRIPTION

This module provides a small framework to abstract logics. It was mostly thought to have a place for isolated business-logic that does neither fit in the MVC concepts controllers nor its models.

Logic Modules

  package FooLogic;
  use warnings;
  use strict;

  use Class::AbstractLogic-base;

  # ... action definitions ...

  1;

You can create a new logic module easily. By useing Class::AbstractLogic with the postfix -base you request the installation of action helpers as well as the Class::AbstractLogic::Base class into this modules @ISA.

Action Definitions

  ...
  action 'foo', needs   [qw(field1 field2)], 
                verify  { field1 => sub { ... }, ... },
                sub     { do_stuff_with($_{field1}) };
  ...

The installed helpers are named action, needs and verify. The first defines the actions name. needs accepts either an arrayref with a list of, or a scalar with a single field name that have to be specified in the arguments to this action. The verify hash reference takes a code reference for each key representing an argument name. The code ref gets the value passed in @_ and as $_. If it returns a false value, an error is thrown.

action just looks for a code reference in the stream of its arguments to determine which is the subroutine that actually represents the action. The arguments passed with the call are available in @_ after the first value representing the current logical module object, and also come in the global hash %_ for easier and more readable access. Via &_ you can access other logical classes:

  action 'foo',
     sub { my $res = _('Bar')->bar(baz => 23); ... }

Note however, that the return values of calls to other logic methods will return Class::AbstractLogic::Result objects which you have to deal with. If your action returns a result object, however, it will not be rewrapped in another result, but just returned itself.

Through the logical module object you have access to the config and error methods.

Logic Modules and the Manager, General Usage

  my $calm = Class::AbstractLogic::Manager->new(
    config => { Foo => { foobar => 23 }} );

This creates a new logic module manager. The configuration is logic module specific. In the above example, a logic module registered under Foo will have { foobar => 23 } as its config value.

  $calm->load_logic(Foo => 'FooLogicClass');

This loads the class FooLogicClass and registers it in themanager under the name Foo.

  my $result = $calm->logic('Foo')->foo(field1 => 12, field2 => 13);

This calls the action foo with the arguments field1 and field2 on the logic module registered under the name Foo.

The Result

  if ($result) { print "ok\n" } else { print "not ok\n" }

The boolean value of the result object will be false if an exception was thrown. If the call succeeded, it will evaluate to true and you can access the value via the result method or its value alias.

Logic Exceptions

To provide a facility to handle errors and other exception like things, C:AL has a built-in exception handling facility. Inside of your actions you can just throw an exception, which will propagate up to the place the current action was called from.

  action 'foo',
         sub { my $self = shift;
               $self->throw( foobar => 'Extensive Error Message' ); 
             };

  ...
  my $result = $calm->logic('WithDyingFoo')->foo(bar => 23);

In the above example, the $result will evaluate to false. You can access its error message through the error method, and its error key (the first argument you specified, it's for easier flow handling with exceptions) through the key method. If you need, you can also get to the original exception object through exception.

METHODS

import(@args)

Handles helper installations in your Logic Modules.

import_helpers($target)

Internal method that installs the action, needs and verify helpers in $target.

_handle_action(@args)

Helper Method, creates a new action in a Logic Class.

_handle_needs($spec)

Helper Method, checks and flags the needs specification.

_handle_verify($spec)

Helper Method, checks and flags the verify specification.

AUTHOR

Robert 'phaylon' Sedlacek <phaylon@dunkelheit.at>

LICENSE AND COPYRIGHT

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