File Coverage

blib/lib/Vote/Count/Common.pm
Criterion Covered Total %
statement 106 107 99.0
branch 15 16 93.7
condition n/a
subroutine 22 22 100.0
pod 9 12 75.0
total 152 157 96.8


line stmt bran cond sub pod time code
1 39     39   27243 use strict;
  39         106  
  39         1249  
2 39     39   214 use warnings;
  39         196  
  39         1018  
3 39     39   688 use 5.024;
  39         146  
4              
5             use Moose::Role;
6 39     39   228  
  39         88  
  39         370  
7             use feature qw /postderef signatures/;
8 39     39   226529 no warnings 'experimental';
  39         109  
  39         3979  
9 39     39   277  
  39         78  
  39         2086  
10             use Storable 3.15 'dclone';
11 39     39   272 use Path::Tiny;
  39         650  
  39         2079  
12 39     39   269  
  39         88  
  39         50164  
13             # ABSTRACT: Role shared by Count and Matrix for common functionality. See Vote::Count Documentation.
14              
15             our $VERSION='2.02';
16              
17             =head1 NAME
18              
19             Vote::Count::Common
20              
21             =head1 VERSION 2.02
22              
23             =head1 Synopsis
24              
25             This Role is consumed by Vote::Count and Vote::Count::Matrix. It provides common methods for the Active Set.
26              
27             =cut
28              
29             has 'BallotSet' => ( is => 'ro', isa => 'HashRef', required => 1 );
30              
31             has 'Active' => (
32             is => 'ro',
33             isa => 'HashRef',
34             lazy => 1,
35             builder => '_defaultactive',
36             );
37              
38             has 'VoteValue' => (
39             is => 'ro',
40             isa => 'Int',
41             default => 1,
42             );
43              
44             has 'WithdrawalList' => (
45             is => 'rw',
46             isa => 'Str',
47             required => 0,
48             );
49              
50             has 'PairMatrix' => (
51             is => 'ro',
52             isa => 'Object',
53             lazy => 1,
54             builder => '_buildmatrix',
55             );
56              
57             my $tiebreak =
58 58     58   106 defined( $self->TieBreakMethod() )
  58         93  
  58         109  
59 58 100       1598 ? $self->TieBreakMethod()
60             : 'none';
61             my %args = (
62             BallotSet => $self->BallotSet(),
63 58         1449 Active => $self->Active(),
64             TieBreakMethod => $tiebreak,
65             LogTo => $self->LogTo() . '_matrix',
66             );
67             $args{'PrecedenceFile'} = $self->PrecedenceFile() if $self->PrecedenceFile();
68             $args{'TieBreakerFallBackPrecedence'} = $self->TieBreakerFallBackPrecedence();
69 58 100       1616 return Vote::Count::Matrix->new( %args );
70 58         1652 }
71 58         1819  
72             $self->{'PairMatrix'} = $self->_buildmatrix();
73             }
74 3     3 1 13  
  3         7  
  3         6  
75 3         9 return sort keys( $self->BallotSet()->{'choices'}->%* );
76             }
77              
78 60     60 0 7981 my $active = dclone $self->BallotSet()->{'choices'} ;
  60         106  
  60         98  
79 60         1813 if ( $self->WithdrawalList ) {
80             for my $w (path( $self->WithdrawalList )->lines({ chomp => 1})) {
81             delete $active->{$w};
82 154     154   284 }
  154         282  
  154         229  
83 154         4102 }
84 154 100       5121 return $active;
85 2         47 }
86 8         459  
87             # Force deref
88             $self->{'Active'} = dclone $active;
89 154         3770 # if there is a child PairMatrix, update it too.
90             if ( defined $self->{'PairMatrix'} ) {
91             $self->{'PairMatrix'}{'Active'} = $self->{'Active'};
92 35     35 1 3384 }
  35         72  
  35         64  
  35         70  
93             }
94 35         1458  
95             $self->{'Active'} = $self->_defaultactive();
96 35 100       214 }
97 8         38  
98             # I was typing the equivalent too often. made a method.
99             $self->SetActive( { map { $_ => 1 } $active->@* } );
100             }
101 1     1 1 2  
  1         2  
  1         3  
102 1         4 # Force deref
103             my $active = $self->Active();
104             return dclone $active;
105             }
106 7     7 1 435  
  7         18  
  7         16  
  7         13  
107 7         22 # this deref also happens a lot
  29         90  
108             return ( sort( keys( $self->Active->%* ) ) );
109             }
110 231     231 1 436  
  231         429  
  231         357  
111             delete $self->{'Active'}{$choice};
112 231         8285 }
113 231         6929  
114             return $self->BallotSet()->{'votescast'};
115             }
116              
117 206     206 1 775 unless ( $self->BallotSet()->{'options'}{'rcv'} ) {
  206         344  
  206         310  
118 206         5562 die "VotesActive Method only supports rcv";
119             }
120             my $set = $self->BallotSet();
121 13     13 1 3843 my $active = $self->Active();
  13         22  
  13         18  
  13         18  
122 13         40 my $activeCount = 0;
123             LOOPVOTESACTIVE:
124             for my $B ( values $set->{ballots}->%* ) {
125 44     44 1 111 for my $V ( $B->{'votes'}->@* ) {
  44         70  
  44         70  
126 44         1200 if ( defined $active->{$V} ) {
127             $activeCount += $B->{'count'};
128             next LOOPVOTESACTIVE;
129 6     6 1 13 }
  6         10  
  6         10  
130 6 50       189 }
131 0         0 }
132             return $activeCount;
133 6         147 }
134 6         158  
135 6         15 if ( $self->BallotSet()->{'options'}{'rcv'} ) {
136             return 'rcv';
137 6         24 }
138 36         62 elsif ( $self->BallotSet()->{'options'}{'range'} ) {
139 39 100       75 return 'range';
140 33         49 }
141 33         54 else {
142             die "BallotSetType is undefined or unknown type.";
143             }
144             }
145 6         22  
146             return $self->BallotSet()->{'ballots'};
147             }
148 48     48 0 1216  
  48         80  
  48         81  
149 48 100       1150 1;
    100          
150 42         230  
151             =head1 Usage
152              
153 5         31 This role is consumed by Vote::Count and Vote::Count::Matrix, providing a common set of functions to all Vote::Count objects.
154              
155             =head1 new
156 1         11  
157             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.
158              
159             use Vote::Count;
160 96     96 0 3379 use Vote::Count::ReadBallots;
  96         192  
  96         144  
161 96         2596 my $Election = Vote::Count->new( BallotSet => read_ballots( $ballotfile ) );
162              
163             =head1 Optional Paramters to Vote::Count
164              
165             =head2 Active
166              
167             Sets the Active Set at creation. See L<Active Sets>.
168              
169             =head2 VoteValue
170              
171             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.
172              
173             =head2 LogTo
174              
175             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>.
176              
177             'LogTo' => '/logging_path/election_name'
178              
179             See L<Vote::Count::Log> for more informationand and additional log path options.
180              
181             =head1 Logging Methods
182              
183             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.
184              
185             For more detail, see L<Vote::Count::Log>.
186              
187             =head1 Active Sets
188              
189             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.
190              
191             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.
192              
193             =head2 Active
194              
195             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">.
196              
197             =head2 GetActive
198              
199             Returns a hashref containing a copy of the Active Set.
200              
201             =head2 GetActiveList
202              
203             Returns a simple array of the members of the Active Set.
204              
205             =head2 ResetActive
206              
207             Sets the Active Set to the full choices list of the BallotSet.
208              
209             =head2 SetActive
210              
211             Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True.
212              
213             =head2 SetActiveFromArrayRef
214              
215             Same as SetActive except it takes an ArrayRef of the choices to be set as Active.
216              
217             =head1 Vote::Count Methods
218              
219             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.
220              
221             =head2 BallotSet
222              
223             Get BallotSet
224              
225             =head2 PairMatrix
226              
227             Get a Matrix Object for the Active Set. Generated and cached on the first request.
228              
229             =head2 UpdatePairMatrix
230              
231             Regenerate and cache Matrix with current Active Set.
232              
233             =head2 VotesCast
234              
235             Returns the number of votes cast.
236              
237             =head2 VotesActive
238              
239             Returns the number of non-exhausted ballots based on the current Active Set.
240              
241             =head2 new
242              
243             Has the following Attributes:
244              
245             =head2 WithdrawalList
246              
247             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.
248              
249             =head2 Choices
250              
251             Returns an array of all of the Choices in the Ballot Set.
252              
253             =head2 GetActiveList
254              
255             Returns a simple array of the members of the Active Set.
256              
257             =head2 ResetActive
258              
259             Sets the Active Set to the full choices list of the BallotSet.
260              
261             =head2 SetActive
262              
263             Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True.
264              
265             =head2 SetActiveFromArrayRef
266              
267             Same as SetActive except it takes an ArrayRef of the choices to be set as Active.
268              
269             =head2 Defeat
270              
271             Remove $choice from current Active List.
272              
273             $Election->Defeat( $choice );
274             $Election->logv( "Defeated $choice");
275              
276             =cut
277              
278             #FOOTER
279              
280             =pod
281              
282             BUG TRACKER
283              
284             L<https://github.com/brainbuz/Vote-Count/issues>
285              
286             AUTHOR
287              
288             John Karr (BRAINBUZ) brainbuz@cpan.org
289              
290             CONTRIBUTORS
291              
292             Copyright 2019-2021 by John Karr (BRAINBUZ) brainbuz@cpan.org.
293              
294             LICENSE
295              
296             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>.
297              
298             SUPPORT
299              
300             This software is provided as is, per the terms of the GNU Public License. Professional support and customisation services are available from the author.
301              
302             =cut
303