Tell the user that they're an idiot in more helpful ways
[catagits/Reaction.git] / lib / Reaction / InterfaceModel / Collection.pm
CommitLineData
7adfd53f 1package Reaction::InterfaceModel::Collection;
2
f670cfd0 3use Reaction::Class;
7adfd53f 4use Scalar::Util qw/refaddr blessed/;
f670cfd0 5use aliased 'Reaction::Meta::InterfaceModel::Object::DomainModelAttribute';
7adfd53f 6
7# WARNING - DANGER: this is just an RFC, please DO NOT USE YET
8
81393881 9use namespace::clean -except => [ qw(meta) ];
10extends "Reaction::InterfaceModel::Object";
7adfd53f 11
81393881 12
13
14# consider supporting slice, first, iterator, last etc.
15# pager functionality should probably be a role
16
17# IM objects don't have write methods because those are handled through actions,
18# no support for write actions either unless someone makes a good case for it
19# many models may not even be writable, so we cant make that assumption...
20
21# I feel like we should hasa result_class or object_class ?
22# having this here would remove a lot of PITA complexity from
23# ObjectClass and SchemaClass when it comes to munging with internals
24
25#Answer: No, because collections should be able to hold more than one type of object
26
27# ALL IMPLEMENTATIONS ARE TO ILLUSTRATE POSSIBLE BEHAVIOR ONLY. DON'T CONSIDER
28# THEM CORRECT, OR FINAL. JUST A ROUGH DRAFT.
29
30#domain_models are 'ro' unless otherwise specified
31has _collection_store => (
32 is => 'rw',
33 isa => 'ArrayRef',
34 lazy_build => 1,
35 clearer => "_clear_collection_store",
36 metaclass => DomainModelAttribute,
37 );
38
39has 'member_type' => (is => 'ro', isa => 'ClassName');
40sub _build__collection_store { [] };
41sub members {
42 my $self = shift;
43 return @{ $self->_collection_store };
7adfd53f 44};
45
81393881 46#return new member or it's index # ?
47sub add_member {
48 my $self = shift;
49 my $new = shift;
50 confess "Argument passed is not an object" unless blessed $new;
51 confess "Object Passed does not meet constraint isa Reaction::InterfaceModel::Object"
52 unless $new->isa('Reaction::InterfaceModel::Object');
53 my $store = $self->_collection_store;
54 push @$store, $new;
55 return $#$store; #return index # of inserted item
56};
57sub remove_member {
58 my $self = shift;
59 my $rem = shift;
60 confess "Argument passed is not an object" unless blessed $rem;
61 confess "Object Passed does not meet constraint isa Reaction::InterfaceModel::Object"
62 unless $rem->isa('Reaction::InterfaceModel::Object');
63
64 my $addr = refaddr $rem;
65 @{ $self->_collection_store } = grep {$addr ne refaddr $_ } @{ $self->_store };
66};
67
68#that was easy..
69sub count_members {
70 my $self = shift;
71 return scalar @{ $self->_collection_store };
72};
73
74__PACKAGE__->meta->make_immutable;
75
76
7adfd53f 771;
78
79=head1 NAME
80
81Reaction::InterfaceModel::Collection - Generic collections of
b8faba69 82L<Reaction::InterfaceModel::Object>s
7adfd53f 83
84=head1 DESCRIPTION
85
86The base class for C<InterfaceModel::Collection>s. The functionality implemented here
87is minimal and it is expected that specialized collections be built by sublclassing
88this and exploiting the roles system.
89
90=head1 METHODS
91
92=head2 members
93
94Returns a list containing all known members of the collection
95
96=head2 add_member $object
97
98Will add the object passed to the collection
99
100=head2 remove_member $object
101
102Removed the object passed from the collection, if present
103
104=head2 count_members
105
106Returns the number of objects in the collection.
107
108=head1 ATTRIBUTES
109
110=head2 _collection_store
111
112Read-write & lazy_build. Holds the arrayref where the collection of objects is
113presently stored. Has a clearer of C<_clear_collection_store> and a predicate of
114 C<_has_collection_store>.
115
116=head1 PRIVATE METHODS
117
89939ff9 118_build__collection_store
7adfd53f 119
120Builder method for attribute_collection_store, returns an empty arrayref
121
122=head1 AUTHORS
123
124See L<Reaction::Class> for authors.
125
126=head1 LICENSE
127
128See L<Reaction::Class> for the license.
129
130=cut