File Coverage

blib/lib/Games/QuizTaker.pm
Criterion Covered Total %
statement 85 143 59.4
branch 17 38 44.7
condition 2 3 66.6
subroutine 13 16 81.2
pod 3 6 50.0
total 120 206 58.2


line stmt bran cond sub pod time code
1             package Games::QuizTaker;
2             {
3 4     4   119113 use strict;
  4         11  
  4         167  
4 4     4   11207 use Text::Wrap;
  4         16273  
  4         260  
5 4     4   34 use Fcntl qw/:flock/;
  4         13  
  4         621  
6 4     4   24 use Carp;
  4         8  
  4         293  
7 4     4   5085 use Data::Dumper;
  4         49784  
  4         341  
8 4     4   5829 use Object::InsideOut;
  4         261132  
  4         33  
9 4     4   434 use vars qw($TESTONLY $VERSION);
  4         9  
  4         238  
10 4     4   2956 use Games::QuizTaker::IO;
  4         11  
  4         2102  
11              
12             $VERSION='2.1';
13             my $questions={};
14             my %Randoms=();
15             my @Randoms=();
16             my %Test_Questions=();
17             my %Test_Answers=();
18             my $t;
19              
20             my @FileName :Field('Standard'=>'FileName','Type'=>'LIST');
21             my @AnswerDelimiter :Field('Standard'=>'AnswerDelimiter','Type'=>'LIST');
22             my @FileLength :Field('Standard'=>'FileLength','Type'=>'NUMERIC');
23             my @Delimiter :Field('Standard'=>'Delimiter','Type'=>'LIST');
24             my @MaxQuestions :Field('Standard'=>'MaxQuestions','Type'=>'NUMERIC');
25             my @Score :Field('Standard'=>'Score','Type'=>'NUMERIC');
26            
27             my %init_args :InitArgs=(
28             'FileName'=>{ # Name of file with questions
29             'Regex' => qr/^FileName$/i,
30             'Mandatory' => 1,
31             },
32             'AnswerDelimiter'=>{ # This is the delimiter that separates multiple answers
33             'Regex'=>qr/AnswerDelimiter/i, # It is a space by default
34             'Default'=>" ",
35             },
36             'FileLength'=>{ # This is the number of questions in the file
37             'Regex'=>qr/FileLength/, # It is set when the question file is loaded
38             'Default'=>0
39             },
40             'Delimiter'=>{ # This is the delimiter that separates the questions and choices.
41             'Regex'=>qr/Delimiter/i, # It is the pipe | character by default
42             'Default'=>"|"
43             },
44             'MaxQuestions'=>{ # This is the maximum number of questions that can be asked for the test
45             'Regex'=>qr/MaxQuestions/,
46             'Default'=>undef
47             },
48             'Score'=>{ # This controls whether or not you want an overall score printed out
49             'Regex'=>qr/Score/i,
50             'Default'=>undef
51             },
52             );
53            
54             sub _init :Init{
55 5         3892 my ($self,$args)=@_;
56 5 50       23 if(exists($args->{'FileName'})){
57 5         34 $self->set(\@FileName,$args->{'FileName'});
58             }
59 5 50       196 if(exists($args->{'AnswerDelimiter'})){
60 5         23 $self->set(\@AnswerDelimiter,$args->{'AnswerDelimiter'});
61             }
62 5 50       125 if(exists($args->{'Delimiter'})){
63 5         25 $self->set(\@Delimiter,$args->{'Delimiter'});
64             }
65 5 100       109 if(exists($args->{'Score'})){
66 1         4 $self->set(\@Score,$args->{'Score'});
67             }
68 5 50       36 if(exists($args->{'MaxQuestions'})){
69 0         0 $self->set(\@MaxQuestions,$args->{'MaxQuestions'});
70             }
71 5 50       19 if(exists($args->{'FileLength'})){
72 5         21 $self->set(\@FileLength,$args->{'FileLength'});
73             }
74 5         246 my $ad=$self->get_AnswerDelimiter;
75 5         143 my $dl=$self->get_Delimiter;
76 5 100       135 if($ad eq $dl){ croak"The Delimiter and Answer Delimiter are the same!"; }
  1         219  
77 4     4   25 }
  4         37  
  4         31  
78            
79             sub load{
80 3     3 1 1779 my $self=shift;
81 3         76 my $delimiter=$self->get_Delimiter;
82 3         83 my $file=$self->get_FileName;
83 3         21 my ($question_number,$count);
84            
85 3 50       214 open(FH,"$file")||croak"Can't open $file: $!";
86 3         30 flock(FH,LOCK_SH);
87 3         114 while(){
88 21         27 my @sorter;
89 21 100 66     144 if(/^$/ or /^#/){}else{
90 19         24 $count++;
91 19         56 my $sep=qq"\\$delimiter";
92 19         206 @sorter=split /$sep/;
93 19         37 $question_number=shift @sorter;
94 19         30 my $ref=\@sorter;
95 19         110 $$questions{$question_number}=$ref;
96             }
97             }
98 3         23 flock(FH,LOCK_UN);
99 3         39 close FH;
100 3         95 $self->set_FileLength($count);
101             }
102            
103             sub generate{
104 2     2 1 29 my $self=shift;
105 2         44 my $Total_Questions=$self->get_FileLength;
106            
107 2 50       55 if(!defined $self->get_MaxQuestions){
108 2         57 $self->set_MaxQuestions($Total_Questions);
109             }
110            
111 2         55 my $Max_Questions=$self->get_MaxQuestions;
112            
113 2         15 for(1..$Max_Questions){
114 13         107 my $question_number=int(rand($Total_Questions)+1);
115 13 100       33 redo if exists $Randoms{$question_number};
116 10         24 $Randoms{$question_number}=1;
117             }
118              
119 2         10 @Randoms=keys %Randoms;
120 2         11 $self->shuffle(\@Randoms);
121            
122 2         9 for(my $D=0;$D<$Max_Questions;$D++){
123 10         9 $Test_Answers{$Randoms[$D]}=pop @{$$questions{$Randoms[$D]}};
  10         24  
124 10         66 $Test_Questions{$Randoms[$D]} = $$questions{$Randoms[$D]};
125             }
126 2         9 $TESTONLY=$$questions{'1'}[0];
127             }
128            
129             sub test{
130 0     0 1 0 my $self=shift;
131 0         0 my $Answer_Sep=$self->get_AnswerDelimiter;
132 0         0 my $Max=$self->get_MaxQuestions;
133 0         0 my ($answer,$key,$line,$question_answer);
134 0         0 my $question_number=1;
135 0         0 my $number_correct=0;
136 0         0 my $asep=qq"\\$Answer_Sep";
137 0 0       0 system(($^O eq "MSWin32"?'cls':'clear'));
138 0         0 print"\n";
139              
140 0         0 while($question_number<=$Max){
141 0         0 $key=shift @Randoms;
142            
143 0         0 print"Question Number $question_number\n";
144 0         0 $t=$$questions{$key}[0]; #Used for module testing
145 0         0 foreach $line(@{$$questions{$key}}){
  0         0  
146 0         0 Games::QuizTaker::IO::out(wrap("","","$line\n"));
147             }
148              
149 0         0 print"Your Answer: ";
150 0         0 $answer=Games::QuizTaker::IO::in;
151 0         0 chomp($answer);
152 0         0 $answer=uc($answer);
153 0         0 $question_answer=$Test_Answers{$key};
154 0         0 chomp($question_answer);
155 0         0 $question_answer=uc $question_answer;
156 0         0 my $ln=length($question_answer);
157              
158 0 0       0 if($ln>1){
159 0 0       0 if($question_answer!~/$Answer_Sep/){
160 0         0 warn"Answer_Delimiter doesn't match internally";
161             }
162 0 0       0 if($Answer_Sep eq " "){ }else{
163 0         0 $question_answer=~s/$asep/ /;
164             }
165 0         0 $question_answer=$self->answer_sort($question_answer);
166 0         0 $answer=$self->answer_sort($answer);
167             }
168              
169 0 0       0 if("$answer" eq "$question_answer"){
170 0         0 print"That is correct!!\n\n";
171 0         0 $question_number++;
172 0         0 $number_correct++;
173             }else{
174 0         0 print"That is incorrect!!\n";
175 0         0 print"The correct answer is $question_answer.\n\n";
176 0         0 $question_number++;
177             }
178             }
179 0         0 my $Final=$self->get_Score;
180 0 0       0 if(defined $Final){
181 0         0 $self->Final($number_correct,$Max);
182 0         0 return;
183             }else{
184 0         0 return;
185             }
186             }
187              
188             sub answer_sort{
189 0     0 0 0 my ($self,$answer)=@_;
190 0         0 my @array=split //,$answer;
191 0         0 my @sorted=sort @array;
192 0         0 $answer=join ' ',@sorted;
193 0         0 return $answer;
194             }
195              
196             sub Final{
197 0     0 0 0 my ($self,$Correct,$Max)=@_;
198            
199 0 0       0 if($Correct >= 1){
200 0         0 my $Percentage=($Correct/$Max)*100;
201 0         0 print"You answered $Correct out of $Max correctly.\n";
202 0         0 printf"For a final score of %02d%%\n",$Percentage;
203 0         0 return;
204             }else{
205 0         0 print"You answered 0 out of $Max correctly.\n";
206 0         0 print"For a final score of 0%\n";
207 0         0 return;
208             }
209             }
210             sub shuffle{
211             ## Fisher-Yates shuffle ##
212 2     2 0 5 my ($self,$array)=@_;
213 2         3 my $x;
214 2         10 for($x=@$array;--$x;){
215 8         12 my $y=int rand ($x+1);
216 8 100       20 next if $x == $y;
217 4         16 @$array[$x,$y]=@$array[$y,$x];
218             }
219             }
220             sub DESTROY{
221 6     6   3639 my $self=shift;
222 6         521 unlink $self;
223             }
224             }
225             1;
226             __END__