File Coverage

blib/lib/Test/AskAnExpert/Interface/File.pm
Criterion Covered Total %
statement 66 67 98.5
branch 16 20 80.0
condition 3 6 50.0
subroutine 15 15 100.0
pod 4 4 100.0
total 104 112 92.8


line stmt bran cond sub pod time code
1             package Test::AskAnExpert::Interface::File;
2              
3 1     1   886 use strict;
  1         2  
  1         32  
4 1     1   6 use warnings;
  1         1  
  1         33  
5 1     1   22 use base qw(Test::AskAnExpert::Interface);
  1         2  
  1         2746  
6              
7             our $VERSION = 0.5;
8              
9 1     1   7 use File::Spec::Functions;
  1         1  
  1         84  
10 1     1   5 use File::Path;
  1         1  
  1         44  
11              
12 1     1   4 use Test::AskAnExpert::Question;
  1         1  
  1         557  
13              
14             =head1 NAME
15              
16             Test::AskAnExpert::Interface::File - File based human interface layer for Test::AskAnExpert
17              
18             =head1 SYNOPSIS
19              
20             In the test:
21              
22             use Test::AskAnExpert import => [qw(is_yes)],plan => 2;
23              
24             Test::AskAnExpert->initialize('Test::AskAnExpert::Interface::File',directory => '/home/tester');
25              
26             is_yes("Does the source code of Foo::Bar conform to in house style spec 7.9 subsection a?","style");
27             is_yes("Could a child understand the underlying algorithm of Foo::Bar?","simple");
28              
29             For the expert:
30              
31             # This assumes *nix, because thats what experts use, right?
32             % cd /home/tester
33             % cat 1.q
34             style
35             ----------
36             Does the source code of Foo::Bar conform to in house style spec 7.9 subsection a?
37             % touch 1.y # The test will recieve an answer of yes, passing in this case.
38             % cat 2.q
39             simple
40             ----------
41             Could a child understand the underlying algorithm of Foo::Bar?
42             % echo "A child would not understand the sexual innuendo used in the variable \
43             % names. Please consider being more professional to conform to company expectations." \
44             % > 2.n # The test will recieve an answer of no, failing in this case and
45             # providing the message in the file as diagnostics.
46              
47              
48             =head1 DESCRIPTION
49              
50             Test::AskAnExpert::Interface::File creates files containing the asked questions
51             and recieves the answer by checking for similarly named files to receive
52             answers.
53              
54             =head2 C arguments
55              
56             Test::AskAnExpert::Interface::File takes its initializing agruments in a hash
57             passed to Test::AskAnExpert::initialize after the interface name.
58              
59             =over 4
60              
61             =item directory
62              
63             Path to the directory (relative or absolute) in which to place the question
64             files and search for the answer files. If it does not exist it will be created
65             during the test and destroyed afterward.
66              
67             If no directory is specified it defaults to the current working directory.
68              
69             =back
70              
71             =head2 Question Files
72              
73             When the test asks a question (through any of is_yes,is_no, or ask)
74             Test::AskAnExpert::Interface::File creates a file with the name $question_id.q
75             contaning the test name and question being asked. The expert is expected to
76             read the question and create one of the three types of answer files specified
77             in the section L.
78              
79             These will be deleted after the test.
80              
81             =head2 Answer Files
82              
83             There are three types of answer file: a yes file, a no file, and a skip file,
84             and their names suggest the type of answer provided to the test.
85              
86             These files should be placed in the same directory as the question files by
87             the expert answering the questions. The $question_id is the name of the
88             question file before the '.q' extension.
89              
90             =over 4
91              
92             =item yes file
93              
94             Yes files have the name $question_id.y and optionally contain commentary about
95             the reason for the answer being yes.
96              
97             =item no file
98              
99             No files are like yes files except they indicate a no answer, contain reasons
100             for the answer being no, and are named $question_id.n .
101              
102             =item skip file
103              
104             Skip files indicate the test should be skipped and contain a reason for the
105             skip (experts caught outside their expertise should use these). They are named
106             expectedly $question_id.s .
107              
108             =back
109              
110             All answer files are cleaned up after the test.
111              
112             =cut
113              
114             sub load {
115 3     3 1 1553 my $class = shift;
116 3         7 my %args = @_;
117 3         5 my $self = {};
118 3         6 $self->{_nextid} = 0;
119 3   100     11 $self->{_dir} = $args{directory} ||= '.';
120 3         6 $self->{_questions} = [];
121              
122 3 100       48 unless( -e $self->{_dir}) {
123 1         3 $self->{_dircreat} = 1;
124 1 50       231 mkpath($self->{_dir}) or return undef;
125             }
126              
127 3         14 bless $self,$class;
128             }
129              
130             sub submit {
131 1     1 1 3 my ($self,$question,$name) = @_;
132            
133 1         9 my $Qobj = Test::AskAnExpert::Question->new(
134             question =>$question,
135             name =>$name,
136             id =>$self->{_nextid});
137              
138 1         2 push @{$self->{_questions}},$self->{_nextid};
  1         3  
139              
140 1         2 $self->{_nextid}++;
141              
142 1 50 0     9 open my $qfile, '>', $self->_get_filename($Qobj->id ,"q") or
143             $self->err("Could not open question file: $!") and return undef;
144              
145 1         33 print $qfile <
146             $name
147             ---------
148             $question
149             QUESTION
150              
151 1         77 close $qfile;
152              
153 1         14 return $Qobj;
154             }
155              
156             sub has_answer {
157 9     9 1 3519 my ($self,$Qobj) = @_;
158              
159 9         20 my @names = map { $self->_get_filename($Qobj->id,$_) } qw(y n s);
  27         73  
160              
161 9         25 foreach (@names) {
162 20 100       351 return 1 if -e $_;
163             }
164              
165 2         996 return 0;
166             }
167              
168             sub answer {
169 5     5 1 578 my ($self,$Qobj) = @_;
170              
171 5 100 50     13 $self->err('Question does not have an answer yet') and return undef unless $self->has_answer($Qobj);
172 4         13 my $id = $Qobj->id;
173              
174 4 100       13 $Qobj->answer('yes',scalar $self->_getcomments($id,'y')), return 1 if $self->_is_y($id);
175 3 100       10 $Qobj->answer('no',scalar $self->_getcomments($id,'n')), return 1 if $self->_is_n($id);
176 1 50       8 $Qobj->skip(scalar $self->_getcomments($id,'s')), return 1 if $self->_is_s($id);
177              
178 0         0 return undef;
179             }
180              
181             sub _get_filename {
182 49     49   370 my ($self,$id,$suffix) = @_;
183            
184 49         10526 return catfile($self->{_dir},"question-$id.$suffix");
185             }
186              
187             sub _getcomments {
188 4     4   9 my ($self,$id,$suffix) = @_;
189              
190 4         18 open my $commentfile,'<',$self->_get_filename($id,$suffix);
191 4         143 my @commentlines = <$commentfile>;
192 4         110 close $commentfile;
193            
194 4 50       102 return wantarray ? @commentlines : join '',@commentlines;
195             }
196              
197             foreach my $suffix (qw(y n s)){
198 1     1   5 no strict 'refs';
  1         1  
  1         184  
199             *{__PACKAGE__."::_is_$suffix"} = sub {
200 8     8   12 my ($self,$id) = @_;
201 8         15 return -e $self->_get_filename($id,$suffix);
202             };
203             }
204              
205             sub DESTROY {
206 3     3   11 my $self = shift;
207              
208 3         6 foreach my $qid (@{$self->{_questions}}) {
  3         10  
209 1         4 unlink glob catfile $self->_get_filename($qid,"*");
210             }
211              
212 3 100       150 rmdir $self->{_dir} if $self->{_dircreat};
213             }
214              
215             =head1 TODO
216              
217             Add a preserve option that prevents cleanup of answers to leave an auditable
218             trail.
219              
220             =head1 AUTHOR
221              
222             Edgar A. Bering, Etrizor@cpan.orgE
223              
224             =head1 COPYRIGHT AND LICENSE
225              
226             Copyright (C) 2007 by Edgar A. Bering
227              
228             This library is free software; you can redistribute it and/or modify
229             it under the terms of the Artistic 2.0 liscence as provided in the
230             LICENSE file of this distribution.
231              
232             =cut
233              
234             1;