Abilities

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


0.3       2012-12-28 17:15:01 Asia/Jerusalem
	[ BACKWARDS COMPATIBILITY BROKEN ]
	- Actions and features can now have constraints. When an action/features
	  doesn't have any, then it's really a yes/no (have/don't) option.
	  When an action/feature does have constraints, then it's no longer
	  a yes/no option. This allows more finer grained control over
	  abilities.
	- The can_perform() method now can only take one action, not a list.
	  It now also takes an optional constraint. Same goes for has_feature().
	- The required actions() method in Abilities.pm and features() method
	  in Abilities/Features.pm now expects a different return structure,
	  read the docs for more info
	- Abilities::Scoped is removed since Abilities now provides the
	  same functionality with the new constraints paradigm

	[ VARIOUS CHANGES ]
	- Now using Any::Moose instead of Moose
	- Changed the names of Abilities::assigned_role() and Abilities::belongs_to()
	  (they were the same method) to Abilities::assigned_role() and
	  added a deprecation warning for the previous two

LICENSE  view on Meta::CPAN

    Holder, and derivatives of that collection of files created through
    textual modification. 
  - "Standard Version" refers to such a Package if it has not been modified,
    or has been modified in accordance with the wishes of the Copyright
    Holder. 
  - "Copyright Holder" is whoever is named in the copyright or copyrights for
    the package. 
  - "You" is you, if you're thinking about copying or distributing this Package.
  - "Reasonable copying fee" is whatever you can justify on the basis of media
    cost, duplication charges, time of people involved, and so on. (You will
    not be required to justify it to the Copyright Holder, but only to the
    computing community at large as a market that must bear the fee.) 
  - "Freely Available" means that no fee is charged for the item itself, though
    there may be fees involved in handling the item. It also means that
    recipients of the item may redistribute it under the same conditions they
    received it. 

1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.

README  view on Meta::CPAN


VERSION
    version 0.5

SYNOPSIS
            package User;
        
            use Moose; # or Moo
            with 'Abilities';
        
            # ... define required methods ...
        
            # somewhere else in your code:

            # get a user object that consumed the Abilities role
            my $user = MyApp->get_user('username'); # $user is a User object

            # check if the user is able to do something
            if ($user->can_perform('something')) {
                    do_something();
            } else {

README  view on Meta::CPAN

  (PAID) SUBSCRIPTION-BASED WEB SERVICES
    Apart from the scenario described above, this module also provides
    optional support for subscription-based web services, such as those
    where customers subscribe to a certain paid (or free, doesn't matter)
    plan from a list of available plans (GitHub is an example of such a
    service). This functionality is also implemented as a Moo(se) role, in
    the Abilities::Features module provided with this distribution. Read its
    documentation for detailed information.

REQUIRED METHODS
    Classes that consume this role are required to implement the following
    methods:

  roles()
    Returns a list of all role names that a user object belongs to, or a
    role object inherits from.

    Example return structure:

            ( 'moderator', 'supporter' )

    NOTE: In previous versions, this method was required to return an array
    of role objects, not a list of role names. This has been changed in
    version 0.3.

  actions()
    Returns a list of all action names that a user object has been
    explicitely granted, or that a role object has been granted. If a
    certain action is constrained, then it should be added to the list as an
    array reference with two items, the first being the name of the action,
    the second being the name of the constraint.

    Example return structure:

            ( 'create_posts', ['edit_posts', 'only_his'], 'comment_on_posts' )

    NOTE: In previous versions, this method was required to return an array
    of action objects, not a list of action names. This has been changed in
    version 0.3.

  is_super()
    This is a boolean attribute that both user and role objects should have.
    If a user/role object has a true value for this attribute, then they
    will be able to perform any action, even if it wasn't granted to them.

  get_role( $name )
    This is a method that returns the object of the role named $name.

README  view on Meta::CPAN

    "assigned_role('devs')" returns false).

  abilities()
    Returns a hash reference of all the abilities a user/role object can
    perform, after consolidating abilities inherited from roles (including
    recursively) and directly granted. Keys in the hash-ref will be names of
    actions, values will be 1 (for yes/no actions) or a single-item
    array-ref with the name of a constraint (for constrained actions).

UPGRADING FROM v0.2
    Up to version 0.2, "Abilities" required the "roles" and "actions"
    attributes to return objects. While this made it easier to calculate
    abilities, it made this system a bit less flexible.

    In version 0.3, "Abilities" changed the requirement such that both these
    attributes need to return strings (the names of the roles/actions). If
    your implementation has granted roles and actions stored in a database
    by names, this made life a bit easier for you. On other implementations,
    however, this has the potential of requiring you to write a bit more
    code. If that is the case, I apologize, but keep in mind that you can
    still store granted roles and actions any way you want in a database
    (either by names or by references), just as long as you correctly
    provide "roles" and "actions".

    Unfortunately, in both versions 0.3 and 0.4, I made a bit of a mess that
    rendered both versions unusable. While I documented the "roles"
    attribute as requiring role names instead of role objects, the actual
    implementation still required role objects. This has now been fixed, but
    it also meant I had to add a new requirement: consuming classes now have
    to provide a method called "get_role()" that takes the name of a role
    and returns its object. This will probably means loading the role from a
    database and blessing it into your role class that also consumes this
    module.

    I apologize for any inconvenience this might have caused.

AUTHOR
    Ido Perlmuter, "<ido at ido50 dot net>"

lib/Abilities.pm  view on Meta::CPAN


version 0.5

=head1 SYNOPSIS

	package User;
	
	use Moose; # or Moo
	with 'Abilities';
	
	# ... define required methods ...
	
	# somewhere else in your code:

	# get a user object that consumed the Abilities role
	my $user = MyApp->get_user('username'); # $user is a User object

	# check if the user is able to do something
	if ($user->can_perform('something')) {
		do_something();
	} else {

lib/Abilities.pm  view on Meta::CPAN


Apart from the scenario described above, this module also provides optional
support for subscription-based web services, such as those where customers
subscribe to a certain paid (or free, doesn't matter) plan from a list
of available plans (GitHub is an example of such a service). This functionality
is also implemented as a Moo(se) role, in the L<Abilities::Features> module provided
with this distribution. Read its documentation for detailed information.

=head1 REQUIRED METHODS

Classes that consume this role are required to implement the following
methods:

=head2 roles()

Returns a list of all role names that a user object belongs to, or a role object
inherits from.

Example return structure:

	( 'moderator', 'supporter' )

NOTE: In previous versions, this method was required to return
an array of role objects, not a list of role names. This has been changed
in version 0.3.

=cut

requires 'roles';

=head2 actions()

Returns a list of all action names that a user object has been explicitely granted,
or that a role object has been granted. If a certain action is constrained, then
it should be added to the list as an array reference with two items, the first being
the name of the action, the second being the name of the constraint.

Example return structure:

	( 'create_posts', ['edit_posts', 'only_his'], 'comment_on_posts' )

NOTE: In previous versions, this method was required to return
an array of action objects, not a list of action names. This has been changed
in version 0.3.

=cut

requires 'actions';

=head2 is_super()

This is a boolean attribute that both user and role objects should have.

lib/Abilities.pm  view on Meta::CPAN

	# merge all abilities
	while (scalar @hashes) {
		$abilities = merge($abilities, shift @hashes);
	}

	return $abilities;
}

=head1 UPGRADING FROM v0.2

Up to version 0.2, C<Abilities> required the C<roles> and C<actions>
attributes to return objects. While this made it easier to calculate
abilities, it made this system a bit less flexible.

In version 0.3, C<Abilities> changed the requirement such that both these
attributes need to return strings (the names of the roles/actions). If your implementation
has granted roles and actions stored in a database by names, this made life a bit easier
for you. On other implementations, however, this has the potential of
requiring you to write a bit more code. If that is the case, I apologize,
but keep in mind that you can still store granted roles and actions
any way you want in a database (either by names or by references), just
as long as you correctly provide C<roles> and C<actions>.

Unfortunately, in both versions 0.3 and 0.4, I made a bit of a mess
that rendered both versions unusable. While I documented the C<roles>
attribute as requiring role names instead of role objects, the actual
implementation still required role objects. This has now been fixed,
but it also meant I had to add a new requirement: consuming classes
now have to provide a method called C<get_role()> that takes the name
of a role and returns its object. This will probably means loading the
role from a database and blessing it into your role class that also consumes
this module.

I apologize for any inconvenience this might have caused.

=head1 AUTHOR

lib/Abilities/Features.pm  view on Meta::CPAN


version 0.5

=head1 SYNOPSIS

	package Customer;
	
	use Moose; # or Moo
	with 'Abilities::Features';
	
	# ... define required methods ...
	
	# somewhere else in your code:

	# get a customer object that consumed the Abilities::Features role
	my $customer = MyApp->get_customer('some_company');
		
	# check if the customer has a certain feature
	if ($customer->has_feature('ssl_encryption')) {
		&initiate_https_connection();
	} else {

lib/Abilities/Features.pm  view on Meta::CPAN

L<Entities::Plan> are customer and plan classes that consume this role.

Just like in L<Abilities>, features can be constrained. For more info,
see L<Abilities/"CONSTRAINTS">.

More information about how these roles work can be found in the L<Entities>
documentation.

=head1 REQUIRED METHODS

Customer and plan classes that consume this role are required to provide
the following methods:

=head2 plans()

This method returns a list of all plan names that a customer has subscribed to,
or that a plan inherits from.

Example return structure:

	( 'starter', 'diamond' )

NOTE: In previous versions, this method was required to return
an array of plan objects, not a list of plan names. This has been changed
in version 0.3.

=cut

requires 'plans';

=head2 features()

This method returns a list of all feature names that a customer has explicitely
been given, or that a plan has. If a certain feature is constrained, then
it should be added to the list as an array reference with two items, the first being
the name of the feature, the second being the name of the constraint.

Example return structure:

	( 'ssh_access', [ 'multiple_users', 5 ] )

NOTE: In previous versions, this method was required to return
an array of feature objects, not a list of feature names. This has been changed
in version 0.3.

=cut

requires 'features';

=head2 get_plan( $name )

Returns the object of the plan named C<$plan>.

lib/Abilities/Features.pm  view on Meta::CPAN

	# merge all features
	while (scalar @hashes) {
		$features = merge($features, shift @hashes);
	}

	return $features;
}

=head1 UPGRADING FROM v0.2

Up to version 0.2, C<Abilities::Features> required the C<plans> and C<features>
attributes to return objects. While this made it easier to calculate
available features, it made this system a bit less flexible.

In version 0.3, C<Abilities::Features> changed the requirement such that both these
attributes need to return strings (the names of the plans/features). If your implementation
has granted plans and features stored in a database by names, this made life a bit easier
for you. On other implementations, however, this has the potential of
requiring you to write a bit more code. If that is the case, I apologize,
but keep in mind that you can still store granted plans and features
any way you want in a database (either by names or by references), just
as long as you correctly provide C<plans> and C<features>.

Unfortunately, in both versions 0.3 and 0.4, I made a bit of a mess
that rendered both versions unusable. While I documented the C<plans>
attribute as requiring plan names instead of plan objects, the actual
implementation still required plan objects. This has now been fixed,
but it also meant I had to add a new requirement: consuming classes
now have to provide a method called C<get_plan()> that takes the name
of a plan and returns its object. This will probably means loading the
plan from a database and blessing it into your plan class that also consumes
this module.

I apologize for any inconvenience this might have caused.

=head1 AUTHOR

t/lib/TestCustomer.pm  view on Meta::CPAN

package TestCustomer;

use Moo;
use namespace::autoclean;

has 'name' => (
	is => 'ro',
	required => 1
);

has 'features' => (
	is => 'ro',
	default => sub { [] }
);

has 'plans' => (
	is => 'ro',
	default => sub { [] }
);

has 'mg' => (
	is => 'ro',
	required => 1,
);

with 'Abilities::Features';

sub get_plan {
	my ($self, $plan) = @_;

	return $self->mg->{$plan};
}

t/lib/TestPlan.pm  view on Meta::CPAN

package TestPlan;

use Moo;
use namespace::autoclean;

has 'name' => (
	is => 'ro',
	required => 1
);

has 'features' => (
	is => 'ro',
	default => sub { [] }
);

has 'plans' => (
	is => 'ro',
	default => sub { [] }
);

has 'mg' => (
	is => 'ro',
	required => 1,
);

with 'Abilities::Features';

sub get_plan {
	my ($self, $plan) = @_;

	return $self->mg->{$plan};
}

t/lib/TestRole.pm  view on Meta::CPAN

package TestRole;

use Moo;
use namespace::autoclean;

has 'name' => (
	is => 'ro',
	required => 1
);

has 'actions' => (
	is => 'ro',
	default => sub { [] }
);

has 'roles' => (
	is => 'ro',
	default => sub { [] }
);

has 'is_super' => (
	is => 'ro',
	default => sub { 0 }
);

has 'mg' => (
	is => 'ro',
	required => 1,
);

with 'Abilities';

sub get_role {
	my ($self, $role) = @_;

	return $self->mg->{$role};
}

t/lib/TestUser.pm  view on Meta::CPAN

package TestUser;

use Moo;
use namespace::autoclean;

has 'name' => (
	is => 'ro',
	required => 1
);

has 'actions' => (
	is => 'ro',
	default => sub { [] }
);

has 'roles' => (
	is => 'ro',
	default => sub { [] }
);

has 'is_super' => (
	is => 'ro',
	default => sub { 0 }
);

has 'mg' => (
	is => 'ro',
	required => 1,
);

with 'Abilities';

sub get_role {
	my ($self, $role) = @_;

	return $self->mg->{$role};
}

t/release-dist-manifest.t  view on Meta::CPAN

  unless ($ENV{RELEASE_TESTING}) {
    require Test::More;
    Test::More::plan(skip_all => 'these tests are for release candidate testing');
  }
}


use Test::More;

eval "use Test::DistManifest";
plan skip_all => "Test::DistManifest required for testing the manifest"
  if $@;
manifest_ok();

t/release-pod-coverage.t  view on Meta::CPAN

  unless ($ENV{RELEASE_TESTING}) {
    require Test::More;
    Test::More::plan(skip_all => 'these tests are for release candidate testing');
  }
}


use Test::More;

eval "use Test::Pod::Coverage 1.08";
plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
  if $@;

eval "use Pod::Coverage::TrustPod";
plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
  if $@;

all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });

t/release-pod-syntax.t  view on Meta::CPAN

BEGIN {
  unless ($ENV{RELEASE_TESTING}) {
    require Test::More;
    Test::More::plan(skip_all => 'these tests are for release candidate testing');
  }
}

use Test::More;

eval "use Test::Pod 1.41";
plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;

all_pod_files_ok();



( run in 0.556 second using v1.01-cache-2.11-cpan-0a6323c29d9 )