-
-
16 Oct 2013 02:25:30 UTC
- Distribution: Role-Subsystem
- Module version: 0.101341
- Source (raw)
- Browse (raw)
- Changes
- Homepage
- How to Contribute
- Repository
- Issues (0)
- Testers (411 / 1 / 0)
- Kwalitee
Bus factor: 1- % Coverage
- License: perl_5
- Activity
24 month- Tools
- Download (15.87KB)
- MetaCPAN Explorer
- Permissions
- Subscribe to distribution
- Permalinks
- This version
- Latest version
NAME
Role::Subsystem - a parameterized role for object subsystems, helpers, and delegates
VERSION
version 0.101341
DESCRIPTION
Role::Subsystem is a parameterized role. It's meant to simplify creating classes that encapsulate specific parts of the business logic related to parent classes. As in the synopsis above, it can be used to write "helpers." The subsystems it creates must have a reference to a parent object, which might be referenced by id or with an actual object reference. Role::Subsystem tries to guarantee that no matter which kind of reference you have, the other kind can be obtained and stored for use.
What??
Okay, imagine you have a big class called Account. An Account is the central point for a lot of behavior, and rather than dump all that logic in one place, you partition it into subsytems. Let's say we want to write a subsystem that handles all of an Account's Services. We might write this:
package Account::ServiceManager; use Moose; use Account; with 'Role::Subsystem' => { ident => 'acct-service-mgr', type => 'Account', what => 'account', getter => sub { Account->retrieve_by_id( $_[0] ) }, }; sub add_service { my ($self, @args) = @_; # ... do some preliminary business logic $self->account->insert_related_rows(...); # ... do some cleanup business logic }
Then you might add to Account.pm:
package Account; sub service_mgr { my ($self) = @_; return Account::ServiceManager->for_account($self); }
Then, to add a service you can write:
$account->service_mgr->add_service(...);
You could also just grab the service manager object and use it as a handle for performing operations.
If you don't have an Account object, just a reference to its id, you could get the service manager like this:
my $service_mgr = Account::ServiceManager->for_account_id( $account_id );
Why?
Here's an overview of everything this role will do for you, in terms of the Account::ServiceManager example above.
It will create the
for_account
andfor_account_id
constructors on your subsystem. (Thefor_account_id
constructor will only be created if agetter
is supplied.)It will defer retrieval of
account
objects if you construct with only aaccount_id
, so that if you never need the full object, you never waste time getting it.It will ensure that any
account
andaccount_id
encountered match thetype
andid_type
types, respectively. This will prevent a bogus identifier from being accepted, only to die later when it can't be used for lazy retrieval.If you create a subsystem object by passing in the parent object (the
account
), it will take a weak reference to it to prevent cyclical references from interfering with garbage collection. If the reference goes away, or if you did not start with a reference, a strong reference will be constructed to allow the subsystem to function efficiently afterward. (This behavior can be disabled, if you never want to take a weak reference.)Swappable Subsystem Implementations
You can also have multiple implementations of a single kind of subsystem. For example, you may eventually want to do something like this:
package Account::ServiceManager; use Moose::Role; with 'Role::Subsystem' => { ... }; requries 'add_service'; requries 'remove_service'; requries 'service_summary';
...and then...
package Account::ServiceManager::Legacy; with 'Account::ServiceManager'; sub add_service { ... };
...and...
package Account::ServiceManager::Simple; with 'Account::ServiceManager'; sub add_service { ... };
...and finally...
package Account; sub settings_mgr { my ($self) = @_; my $mgr_class = $self->schema_version > 1 ? 'Account::ServiceManager::Simple' : 'Account::ServiceManager::Legacy'; return $mgr_class->for_account($self); }
This requires a bit more work, but lets you replace subsystem implementations as fairly isolated units.
PARAMETERS
These parameters can be given when including Role::Subsystem; these are in contrast to the attributes and methods below, which are added to the classe composing this role.
ident
This is a simple name for the role to use when describing itself in messages. It is required.
what
This is the name of the attribute that will hold the parent object, like the
account
in the synopsis above.This attribute is required.
what_id
This is the name of the attribute that will hold the parent object's identifier, like the
account_id
in the synopsis above.If not given, it will be the value of
what
with "_id" stuck on the end.type
This is the type that the
what
must be. It may be a stringly Moose type or an MooseX::Types type. (Or anything else, right now, but anything else will probably cause runtime failures or worse.)This attribute is required.
id_type
This parameter is like
type
, but is used to check thewhat
's id, discussed more below. If not given, it defaults toDefined
.id_method
This is the name of a method to call on
what
to get its id. It defaults toid
.getter
This (optional) attribute supplied a callback that will produce the parent object from the
what_id
.weak_ref
If true, when a subsytem object is created with a defined parent object (that is, a value for
what
), the reference to the object will be weakened. This allows the parent and the subsystem to store references to one another without creating a problematic circular reference.If the parent object is subsequently garbage collected, a new value for
what
will be retreived and stored, and it will not be weakened. To allow this, settingweak_ref
to true requires thatgetter
be supplied.weak_ref
is true by default.ATTRIBUTES
The following attributes are added classes composing Role::Subsystem.
$what
This will refer to the parent object of the subsystem. It will be a value of the
type
type defined when parameterizing Role::Subsystem. It may be lazily computed if it was not supplied during creation or if the initial value was weak and subsequently garbage collected.If the value of
what
when parameterizing Role::Subsystem wasaccount
, that will be the name of this attribute, as well as the method used to read it.$what_id
This method gets the id of the parent object. It will be a defined value of the
id_type
provided when parameterizing Role::Subsystem. It may be lazily computed by calling theid_method
onwhat
as needed.METHODS
for_$what
my $settings_mgr = Account::ServiceManager->for_account($account);
This is a convenience constructor, returning a subsystem object for the given
what
.for_$what_id
my $settings_mgr = Account::ServiceManager->for_account_id($account_id);
This is a convenience constructor, returning a subsystem object for the given
what_id
.AUTHOR
Ricardo Signes <rjbs@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
Module Install Instructions
To install Role::Subsystem, copy and paste the appropriate command in to your terminal.
cpanm Role::Subsystem
perl -MCPAN -e shell install Role::Subsystem
For more information on module installation, please visit the detailed CPAN module installation guide.