package MooseX::Attribute::Restricted; {
	use Moose::Role;
	use version;

=head1 NAME

MooseX::Attribute::Restricted - attribute role that implements public, private
and protected attributes

=head1 VERSION

Version 0.1.0

=head1 SYNOPSIS

	# STEP 1: define your metaclasses
	package Moose::Meta::Method::Accessor::Custom::Mine; {
		use Moose;
		
		extends 'Moose::Meta::Method::Accessor';
		with 'MooseX::Meta::Method::Accessor::Restricted';
	};

	package Moose::Meta::Attribute::Custom::Mine; {
		use Moose;
		
		extends 'Moose::Meta::Attribute';
		with 'MooseX::Attribute::Restricted';
		
		override 'accessor_metaclass' =>
			sub { 'Moose::Meta::Method::Accessor::Custom::Mine' };
	};
	
	# STEP 2: create attributes using those metaclasses
	# ...using per-attribute metaclasses
	package Foo; {
		use Moose;
		
		has 'bar' => (is => 'rw', metaclass => 'Mine', private => 1);
		# bar only accessible from within this class
		
		has 'baz' => (is => 'rw', private => 1);
		# baz uses the default metaclass, so privacy is not enforced
		# (unless the default Moose metaclass adds it)
	}
	
	# ...using a policy
	package Moose::Policy::Mine; {
		use constant 'attribute_metaclass' =>
			sub { 'Moose::Meta::Attribute::Custom::Mine' }
	}
	
	package Foo; {
		use Moose::Policy 'Moose::Policy::Mine'; # all attributes use custom metaclass
		use Moose;
		
		has 'bar' => (is => 'rw', private => 1);
		# bar only accessible within this class
		
		has 'baz' => (is => 'rw', protected => 1);
		# baz only accessible within this class and subclasses
		
		has 'quux' => (is => 'rw');
		# quux public, accessible from anywhere (default)
	};
	
	# subclasses can access protected attributes
	package Bar; {
		use Moose;
		
		extends 'Foo';
		
		sub Bar_bar  { shift->bar }
		sub Bar_baz  { shift->baz }
		sub Bar_quux { shift->quux }
	};
	
	# STEP 3: enjoy restricted access
	package main;
	my $foo = new Foo;
	$foo->bar;  # dies (bar is a private attribute)
	$foo->baz;  # dies (baz is a protected attribute)
	$foo->quux; # OK
	
	my $bar = new Bar; # $bar->bar, baz, quux all behave as above
	$bar->Bar_bar;  # dies (bar is a private attribute)
	$bar->Bar_baz;  # OK (bar is a protected attribute)
	$bar->Bar_quux; # OK (quux is a public attribute)

=head1 DESCRIPTION

C<MooseX::Attribute::Restricted> is a role that implements the concepts of
public, private and protected attributes. This is done in two parts: adding
options to the attribute objects, and enforcing those options in the accessors.
The module you are looking at implements the first part. The second is
implemented by C<L<MooseX::Meta::Method::Accessor::Restricted>>.

The intended usage is for this module to be consumed by an attribute metaclass
of your own, as shown in the SYNOPSIS. This attribute metaclass may then be used
either on a case-by-case basis for each attribute:

	has 'foo' => (is => 'rw', metaclass => 'Mine', protected => 1);
	# `metaclass => 'Mine'` refers to Moose::Meta::Attribute::Custom::Mine,
	# see the Moose docs for more info

or (for better scalability) as part of a L<Moose::Policy> policy:

	package Moose::Policy::Mine; {
		use constant 'attribute_metaclass' =>
			'Moose::Meta::Attribute::Custom::Mine';
	};
	
	package My::Moose::Class; {
		use Moose::Policy 'Moose::Policy::Mine';
		use Moose;
		
		has 'foo' => (is => 'rw', protected => 1);
	};

The concepts of "public", "private" and "protected" as understood by these
modules are explained below. They may differ from your own. C<:-)>

=head2 CONVENTIONS

C<Moose::Meta::Method::Accessor::Custom::Mine> and
C<Moose::Meta::Attribute::Custom::Mine> refer to the classes defined in the
SYNOPSIS.

=head2 TYPES OF ATTRIBUTES

=head3 Public

A public attribute is one that can be accessed from any code. This is the
default for all attributes.

=head3 Private

A private attribute is one that may only be accessed from within the class it is
defined in. Note that this does not prevent you from wrapping access to it
within a class method. So, for example, this still works as you would expect:

	package Foo;
	use Moose;
	
	has 'bar' => (is => 'rw', metaclass => 'Mine', private => 1);
	
	sub do_something {
		my $self = shift;
		
		$self->bar($_[0] * 10);
		return $self->bar;
	}

(Assuming, of course, that you expect to be able to call C<do_something> to set
the value of C<bar> to the first argument multiplied by 10.)

=head3 Protected

A protected attribute may only be accessed from within the class it is defined
in, or any subclasses of that class.

=cut

	our $VERSION = version->new('0.1.0');
	our $AUTH = 'cpan:AANKHEN';
	
	has 'protected' => (is => 'ro', default => 0);
	has 'private'   => (is => 'ro', default => 0);
	
	override '_process_options' => sub {
		my ($class, $name, $options) = @_;
		
		if ($options->{private} && $options->{protected}) {
			confess "Attributes cannot be both private and protected";
		}
		
		super;
	};

=head1 AUTHOR

Aankhen, C<< <aankhen-spamtrap{at}gmail{dot}com> >> (obviously, remove the
-spamtrap)

=head1 DIAGNOSTICS

=over

=item C<An attribute may not be private and protected at the same time.>

Sadly, we cannot yet handle attributes that are both private and protected.
Patches welcome. C<:-)>

=back

=head1 CAVEATS

You I<must> override the C<accessor_metaclass> method in your
C<Moose::Meta::Attribute> subclass, or else access restrictions will not be
enforced.

=head1 DEPENDENCIES

This module requires Moose and Test::Exception to be installed.

=head1 BUGS AND LIMITATIONS

=over 4

=item *

Roles are not correctly supported at present.  I'm still working on it.

=back

Please report any bugs or feature requests to C<bug-moosex-attribute-restricted
at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooseX-Attribute-Restricted>. I
will be notified, and then you'll automatically be notified of progress on your
bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc MooseX::Attribute::Restricted

You can also look for information at:

=over 4

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/MooseX-Attribute-Restricted>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/MooseX-Attribute-Restricted>

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooseX-Attribute-Restricted>

=item * Search CPAN

L<http://search.cpan.org/dist/MooseX-Attribute-Restricted>

=back

=head1 ACKNOWLEDGEMENTS

The authors of Moose, of course, for introducing me to the wonderfully circular
metaverse.

#moose on MAGnet for putting up with my constant alternation between questions
#and illogical conclusions.

mst for always having a better way.

=head1 SEE ALSO

L<Moose>, L<Moose::Meta::Attribute>, L<Moose::Meta::Accessor::Method>.

May also be worth reading for more involved programming: L<Class::MOP>,
L<Class::MOP::Attribute>, L<Class::MOP::Method::Accessor>.

=head1 COPYRIGHT & LICENCE

Copyright 2007 Aankhen, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut
};

1; # End of MooseX::Attribute::Restricted
