File Coverage

blib/lib/Vote/Count/Common.pm
Criterion Covered Total %
statement 94 95 98.9
branch 11 12 91.6
condition n/a
subroutine 20 20 100.0
pod 9 11 81.8
total 134 138 97.1


line stmt bran cond sub pod time code
1 39     39   30765 use strict;
  39         103  
  39         1314  
2 39     39   240 use warnings;
  39         89  
  39         1229  
3 39     39   775 use 5.024;
  39         144  
4              
5             package Vote::Count::Common;
6 39     39   19894 use Moose::Role;
  39         209462  
  39         194  
7              
8 39     39   230844 use feature qw /postderef signatures/;
  39         102  
  39         4378  
9 39     39   291 no warnings 'experimental';
  39         104  
  39         2730  
10              
11 39     39   449 use Storable 3.15 'dclone';
  39         850  
  39         2370  
12 39     39   311 use Path::Tiny;
  39         105  
  39         44584  
13              
14             # ABSTRACT: Role shared by Count and Matrix for common functionality. See Vote::Count Documentation.
15              
16             our $VERSION='2.00';
17              
18             =head1 NAME
19              
20             Vote::Count::Common
21              
22             =head1 VERSION 2.00
23              
24             =head1 Synopsis
25              
26             This Role is consumed by Vote::Count and Vote::Count::Matrix. It provides common methods for the Active Set.
27              
28             =cut
29              
30             has 'BallotSet' => ( is => 'ro', isa => 'HashRef', required => 1 );
31              
32             has 'Active' => (
33             is => 'ro',
34             isa => 'HashRef',
35             lazy => 1,
36             builder => '_defaultactive',
37             );
38              
39             has 'VoteValue' => (
40             is => 'ro',
41             isa => 'Int',
42             default => 1,
43             );
44              
45             has 'WithdrawalList' => (
46             is => 'rw',
47             isa => 'Str',
48             required => 0,
49             );
50              
51 45     45 0 121 sub GetChoices ( $self ) {
  45         107  
  45         89  
52 45         1277 return sort keys( $self->BallotSet()->{'choices'}->%* );
53             }
54              
55 118     118   238 sub _defaultactive ( $self ) {
  118         215  
  118         190  
56 118         3025 my $active = dclone $self->BallotSet()->{'choices'} ;
57 118 100       4345 if ( $self->WithdrawalList ) {
58 2         56 for my $w (path( $self->WithdrawalList )->lines({ chomp => 1})) {
59 8         528 delete $active->{$w};
60             }
61             }
62 118         2773 return $active;
63             }
64              
65 34     34 1 3344 sub SetActive ( $self, $active ) {
  34         69  
  34         62  
  34         57  
66             # Force deref
67 34         1443 $self->{'Active'} = dclone $active;
68             # if there is a child PairMatrix, update it too.
69 34 100       211 if ( defined $self->{'PairMatrix'} ) {
70 8         33 $self->{'PairMatrix'}{'Active'} = $self->{'Active'};
71             }
72             }
73              
74 1     1 1 4 sub ResetActive ( $self ) {
  1         2  
  1         2  
75 1         3 $self->{'Active'} = $self->_defaultactive();
76             }
77              
78             # I was typing the equivalent too often. made a method.
79 6     6 1 396 sub SetActiveFromArrayRef ( $self, $active ) {
  6         15  
  6         13  
  6         11  
80 6         21 $self->SetActive( { map { $_ => 1 } $active->@* } );
  25         75  
81             }
82              
83 43     43 1 92 sub GetActive ( $self ) {
  43         69  
  43         63  
84             # Force deref
85 43         1993 my $active = $self->Active();
86 43         2187 return dclone $active;
87             }
88              
89             # this deref also happens a lot
90 147     147 1 776 sub GetActiveList( $self ) {
  147         244  
  147         229  
91 147         4516 return ( sort( keys( $self->Active->%* ) ) );
92             }
93              
94 13     13 1 5958 sub Defeat ( $self, $choice ) {
  13         21  
  13         19  
  13         16  
95 13         35 delete $self->{'Active'}{$choice};
96             }
97              
98 44     44 1 125 sub VotesCast ( $self ) {
  44         80  
  44         64  
99 44         1262 return $self->BallotSet()->{'votescast'};
100             }
101              
102 6     6 1 13 sub VotesActive ( $self ) {
  6         11  
  6         9  
103 6 50       191 unless ( $self->BallotSet()->{'options'}{'rcv'} ) {
104 0         0 die "VotesActive Method only supports rcv";
105             }
106 6         144 my $set = $self->BallotSet();
107 6         140 my $active = $self->Active();
108 6         13 my $activeCount = 0;
109             LOOPVOTESACTIVE:
110 6         23 for my $B ( values $set->{ballots}->%* ) {
111 36         70 for my $V ( $B->{'votes'}->@* ) {
112 39 100       77 if ( defined $active->{$V} ) {
113 33         52 $activeCount += $B->{'count'};
114 33         58 next LOOPVOTESACTIVE;
115             }
116             }
117             }
118 6         23 return $activeCount;
119             }
120              
121 50     50 0 1240 sub BallotSetType ( $self ) {
  50         102  
  50         92  
122 50 100       1363 if ( $self->BallotSet()->{'options'}{'rcv'} ) {
    100          
123 44         254 return 'rcv';
124             }
125             elsif ( $self->BallotSet()->{'options'}{'range'} ) {
126 5         32 return 'range';
127             }
128             else {
129 1         11 die "BallotSetType is undefined or unknown type.";
130             }
131             }
132              
133 98     98 1 2838 sub GetBallots ( $self ) {
  98         199  
  98         162  
134 98         2742 return $self->BallotSet()->{'ballots'};
135             }
136              
137             1;
138              
139             =head1 Usage
140              
141             This role is consumed by Vote::Count and Vote::Count::Matrix, providing a common set of functions to all Vote::Count objects.
142              
143             =head1 new
144              
145             The only required parameter is BallotSet. The BallotSet is provided by L<Vote::Count::ReadBallots>, you may place the BallotSet in a variable or more typically read it from within the new method.
146              
147             use Vote::Count;
148             use Vote::Count::ReadBallots;
149             my $Election = Vote::Count->new( BallotSet => read_ballots( $ballotfile ) );
150              
151             =head1 Optional Paramters to Vote::Count
152              
153             =head2 Active
154              
155             Sets the Active Set at creation. See L<Active Sets>.
156              
157             =head2 VoteValue
158              
159             Use to set a Vote Value for methods that weight votes. The default value is 1.
160              
161             =head2 LogTo
162              
163             Sets a path and Naming pattern for writing logs with the WriteLogs method. If LogTo is not provided the default location is I</tmp/votecount>.
164              
165             'LogTo' => '/logging_path/election_name'
166              
167             See L<Vote::Count::Log> for more informationand and additional log path options.
168              
169             =head1 Logging Methods
170              
171             Vote::Count writes 3 logs: B<t>erse/brief, B<v>erbose, and B<d>etail. The three logging methods I<logt>, I<logv>, and I<logd> are used to record messages to those respective logs. The WriteLogs method is used to write the logs to disk.
172              
173             For more detail, see L<Vote::Count::Log>.
174              
175             =head1 Active Sets
176              
177             Active sets are a Hash Reference where the keys represent the active choices and the value is true. The VoteCount Object contains an Active Set which can be Accessed via the Active() method which will return a reference to the Active Set (changing the reference will change the active set). The GetActive and SetActive methods break the reference links. GetActiveList returns the Active Set as a sorted list.
178              
179             Many Components will take an argument for $activeset or default to the current Active set of the Vote::Count object, which is defaulted to the Choices defined in the BallotSet.
180              
181             =head2 Active
182              
183             Get Active Set as HashRef to the active set. Changing the new HashRef will change the internal Active Set, GetActive is often preferable as it will return a HashRef that is a copy instead. Active may be used as an optional parameter to L<new|"Optional Paramters to Vote::Count">.
184              
185             =head2 GetActive
186              
187             Returns a hashref containing a copy of the Active Set.
188              
189             =head2 GetActiveList
190              
191             Returns a simple array of the members of the Active Set.
192              
193             =head2 ResetActive
194              
195             Sets the Active Set to the full choices list of the BallotSet.
196              
197             =head2 SetActive
198              
199             Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True.
200              
201             =head2 SetActiveFromArrayRef
202              
203             Same as SetActive except it takes an ArrayRef of the choices to be set as Active.
204              
205             =head1 Vote::Count Methods
206              
207             Most of these are provided by the Role Common and available directly in both Matrix objects and Vote::Count Objects. Vote::Count objects create a child Matrix object: PairMatrix.
208              
209             =head2 BallotSet
210              
211             Get BallotSet
212              
213             =head2 PairMatrix
214              
215             Get a Matrix Object for the Active Set. Generated and cached on the first request.
216              
217             =head2 UpdatePairMatrix
218              
219             Regenerate and cache Matrix with current Active Set.
220              
221             =head2 VotesCast
222              
223             Returns the number of votes cast.
224              
225             =head2 VotesActive
226              
227             Returns the number of non-exhausted ballots based on the current Active Set.
228              
229             =head2 new
230              
231             Has the following Attributes:
232              
233             =head2 WithdrawalList
234              
235             A text file containing choices 1 per line that are withdrawn. Use when a choice may be included in the ballots but should be treated as not-present. Removing a choice from the choices list in a Ballot File will generate an exception from ReadBallots if it appears on any Ballots. Withdrawing a choice will exclude it from the Active Set if it is present in the Ballots.
236              
237             =head2 Active
238              
239             Get Active Set as HashRef to the active set. Changing the new HashRef will change the internal Active Set, GetActive is recommended as it will return a HashRef that is a copy instead.
240              
241             =head2 GetActive
242              
243             Returns a hashref containing a copy of the Active Set.
244              
245             =head2 Choices
246              
247             Returns an array of all of the Choices in the Ballot Set.
248              
249             =head2 GetActiveList
250              
251             Returns a simple array of the members of the Active Set.
252              
253             =head2 ResetActive
254              
255             Sets the Active Set to the full choices list of the BallotSet.
256              
257             =head2 SetActive
258              
259             Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True.
260              
261             =head2 SetActiveFromArrayRef
262              
263             Same as SetActive except it takes an ArrayRef of the choices to be set as Active.
264              
265             =head2 Defeat
266              
267             Remove $choice from current Active List.
268              
269             $Election->Defeat( $choice );
270             $Election->logv( "Defeated $choice");
271              
272             =head2 BallotSet
273              
274             Get BallotSet
275              
276             =head2 GetBallots
277              
278             Get just the Ballots from the BallotSet.
279              
280             =head2 PairMatrix
281              
282             Get a Matrix Object for the Active Set. Generated and cached on the first request.
283              
284             =head2 UpdatePairMatrix
285              
286             Regenerate and cache Matrix with current Active Set.
287              
288             =head2 VotesCast
289              
290             Returns the number of votes cast.
291              
292             =head2 VotesActive
293              
294             Returns the number of non-exhausted ballots based on the current Active Set.
295              
296             =head2 VoteValue
297              
298             Sets a VoteValue for use in weighted systems like STV. The default value is 1. Approval and TopCount are aware of VoteValue for RCV ballots.
299              
300             =cut
301              
302             #FOOTER
303              
304             =pod
305              
306             BUG TRACKER
307              
308             L<https://github.com/brainbuz/Vote-Count/issues>
309              
310             AUTHOR
311              
312             John Karr (BRAINBUZ) brainbuz@cpan.org
313              
314             CONTRIBUTORS
315              
316             Copyright 2019-2021 by John Karr (BRAINBUZ) brainbuz@cpan.org.
317              
318             LICENSE
319              
320             This module is released under the GNU Public License Version 3. See license file for details. For more information on this license visit L<http://fsf.org>.
321              
322             SUPPORT
323              
324             This software is provided as is, per the terms of the GNU Public License. Professional support and customisation services are available from the author.
325              
326             =cut
327