File Coverage

lib/Class/Composite.pm
Criterion Covered Total %
statement 35 40 87.5
branch 5 8 62.5
condition 1 2 50.0
subroutine 10 12 83.3
pod 7 7 100.0
total 58 69 84.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::Composite - Implements Composite patterns
4              
5             =head1 SYNOPSIS
6              
7             =========================
8             Collection implementation
9             =========================
10              
11             use Class::Composite;
12             my $collection = Class::Composite::Container->new();
13             my $element = Class::Composite::Element->new();
14             $collection->addElement( $elem );
15             $elements = $collection->getElements();
16              
17              
18             ========================
19             Composite implementation
20             ========================
21              
22             package graphicBase; # Base for graphics containers and elements
23             sub display {
24             my $self = shift;
25             foreach my $elem (@{$self->getElements()}) {
26             $elem->display();
27             }
28             paint($elem);
29             }
30              
31              
32             package graphicElement;
33             use base qw( Class::Composite::Element graphicBase );
34              
35              
36             package graphicContainer;
37             use base qw( Class::Composite::Container graphicBase );
38              
39              
40             package main;
41             use graphicElement;
42             use graphicContainer;
43             my $element = graphicElement->new();
44             my $container = graphicContainer->new();
45             $container->addElement( $element );
46             $container->display();
47              
48             =head1 DESCRIPTION
49              
50             C is used to provide mechanisms used by C
51             and C. Class::Composite::* implements a Composite pattern (see OO Patterns books and http://www.uni-paderborn.de/cs/ag-schaefer/Lehre/Lehrveranstaltungen/Vorlesungen/Entwurfsmuster/WS0102/DPSA-IVb.pdf for example).
52             A composite pattern is a collection implementation which provides same methods to the container and elements.
53             The reason for using a Composite pattern is to have the same interface to deal with different objects and their containers (collections).
54              
55             If you only need a collection implementation, then you can inherite from Class::Composite::Container and Class::Composite::Element directly.
56             If you need specific method that should be applied to both your container and your elements (which is what the Class::Composite is made for),
57             then you isolate the methods you want to apply on both elements and containers in a specific package.
58             Then, you inherite from both your package and Class::Composite::Element for elements, and Class::Composite::Container for containers.
59              
60             =head1 INHERITANCE
61              
62             Class::Base
63              
64             =cut
65             package Class::Composite;
66              
67 2     2   10 use strict;
  2         2  
  2         54  
68 2     2   9 use warnings::register;
  2         3  
  2         191  
69 2     2   8 use Scalar::Util qw( blessed );
  2         3  
  2         87  
70              
71 2     2   8 use base qw( Class::Base );
  2         3  
  2         12439  
72              
73             our $VERSION = 0.2;
74              
75              
76             =head2 getAll()
77              
78             Returns an array ref of all elements below, whatever their depth or type.
79              
80             =cut
81             sub getAll : method {
82 9     9 1 12 my $self = shift;
83 9         11 my @elems = ();
84 9         10 foreach my $junior ( @{$self->getElements()} ) {
  9         21  
85 8         13 push @elems, $junior;
86 8 50       14 push @elems, @{$junior->getAll} if defined($junior);
  8         23  
87             }
88 9         25 \@elems;
89             }
90              
91              
92             =head2 getLeaves(start, end)
93              
94             Returns all Class::Composite::Element contained in the collection, whatever their depth.
95              
96             =cut
97             sub getLeaves : method {
98 3     3 1 5 my ($self, $start, $last) = @_;
99 3         4 my @elements = ();
100 3         4 foreach my $elem ( @{$self->getElements($start, $last)} ) {
  3         8  
101 10 50       25 defined $elem or next;
102 10 100       29 if ($elem->isa('Class::Composite::Element')) {
103 9         13 push @elements, $elem;
104             }
105             else {
106 1   50     5 my $subElems = $elem->getLeaves() || [];
107 1 50       9 push @elements, @$subElems if (@$subElems);
108             }
109             }
110 3         13 \@elements;
111             }
112              
113              
114             =head2 getElements()
115              
116             Returns the elements just below the current object.
117             Returns []
118             must probably be overriden by child classes.
119              
120             =cut
121 7     7 1 21 sub getElements () : method { [] }
122              
123              
124             =head2 getElement()
125              
126             Returns undef
127             must probably be overriden by child classes
128              
129             =cut
130 0     0 1 0 sub getElement () : method { undef }
131              
132              
133             =head2 nOfElements()
134              
135             Returns undef, to be overriden by child class
136              
137             =cut
138 1     1 1 11 sub nOfElements { }
139              
140              
141             =head2 elementType()
142              
143             Returns the class the element must belongs to, default is
144             Class::Composite.
145             Sets it to undef if you don't want any checking to occur.
146             To be overriden in Child class.
147              
148             =cut
149 11     11 1 44 sub elementType () : method { __PACKAGE__ }
150              
151              
152             =head2 applyToAll( $sub )
153              
154             Applies the subroutine $sub to all elements.
155             The subroutine will receive a collection element as a parameter.
156              
157             =cut
158             sub applyToAll : method {
159 0     0 1 0 my ($self, $sub) = @_;
160 0         0 $sub->( $_ ) foreach ( @{$self->getElements} );
  0         0  
161 0         0 $self;
162             }
163              
164              
165             ##
166             ## Helper method
167             ##
168             sub _warn {
169 1     1   126 warn $_[1].' - '.caller(1)." " . caller(2) . "\n";
170 1         11 undef;
171             }
172              
173              
174             1;
175              
176              
177             __END__