package Test::Smart::Question;

use strict;
use warnings;
use Carp;

=head1 NAME

Test::Smart::Question - Data wrapper for Test::Smart questions


This object provides basic semantics and data encapsulation for Test::Smart
questions, feel free to subclass it as you need when writing Interfaces.


  use Test::Smart::Question;

  $Qobj = Test::Smart::Question->new(question => "I can has cheesburger?",
                                     name     => "Cheesburger",
                                     id       => "Uniq123");

  $Qobj->skip("The person being asked doesn't know how to answer");

  $Qobj->answer('yes','commentary or diagnostics');
  ($answer,$comment) = $Qobj->answer;
  $answer = $Qobj->answer;

=head1 DETAILS

=head2 new(question => $question_text,id => $uniq_id, [name => $test_name,skip => $reason,other_key => $other_value])

The constructor takes its params as a hash, requiring question and id and
optionally taking name and skip. If skip is set it is equivalent to calling
C<< $Qobj->skip("Reason") >> with all of the semantic implications (you can no
longer provide an answer unless you explicitly call C<< $Qobj->test >>).

Test::Smart::Question also stores any other keys given to it in the blessed
hashref for the convinence of any Interface implementer who doesn't need a full
subclass. These should probably be treated as private unless documented
otherwise in the Interface's documentation.


sub new {
  my $class = shift;
  my %args = @_;
  my $self = {};
  $self->{_id}       = $args{id};
  $self->{_question} = $args{question};

  die "Test::Smart::Question requires a question and an id in the constructor"
    unless defined $self->{_id} and $self->{_question};

  $self->{_name}     = $args{name};
  $self->{_skip}     = $args{skip};
  foreach my $key (grep { $_ !~ /question|name|id/ } keys %args) {
    $self->{$key} = $args{$key};
  bless $self,$class;

=head2 question

This is a read only accessor for the question string provided at object
construction. If you try to set question it simply ignores the pass.


sub question {
  my $self = shift;
  return $self->{_question};

=head2 id

Like C<question> but for the constructor set ID.


sub id {
  my $self = shift;
  return $self->{_id};

=head2 name([$new_name])

Mutator for the stored test name. This value is used when answering the
question for TAP output in the same way as the second parameter to C<ok>


sub name {
  my ($self,$name) = @_;
  $self->{_name} = $name if defined($name);
  return $self->{_name};

=head2 skip([$reason])

Sets the internal skip value. Once set it cannot be undefed unless you use
C<< $Qobj->test >> to indicate you do indeed want to test with this Question.
While a skip reason is set the object will silently reject answers submitted to


sub skip {
  my ($self,$reason) = @_;
  $self->{_skip} = $reason if defined($reason);
  return $self->{_skip};

=head2 test

Indicate to the object that you're going to test it, which means it should
accept an answer and clear skip.


sub test {
  my $self = shift;
  $self->{_skip} = undef;

=head2 answer([$answer, $comment])

Mutator for the object's stored answer. When setting it the first parameter
must match C</yes|no/i> and should reflect the answer provided by the person.
If diagnostics or commentary is required it is provided in the $comment param,
though this is optional.

If there is currently a reason for skipping set (either through skip or in the
constructor) then answer will simply return undef and do nothing. You also 
cannot retrieve the answer if skip gets set.


sub answer {
  my ($self,$answer,$comment) = @_;

  return undef if defined($self->{_skip});
  return wantarray ? ($self->{_answer},$self->{_comment}) : $self->{_answer} unless defined($answer);
  croak "Answer must be yes or no, not [$answer]" unless $answer =~ /yes|no/i;

  ($self->{_answer},$self->{_comment}) = ($answer,$comment);
  return wantarray ? ($self->{_answer},$self->{_comment}) : $self->{_answer};


If you want to make a custom interface for Test::Smart look at
L<Test::Smart::Interface>. If you do find the need to write something so
fancy that you must also subclass this, make sure your subclass is a perfect
drop-in replacement or else you'll break Test::Smart itsself.

=head1 SEE ALSO

L<Test::Smart>, L<Test::Smart::Interface>

=head1 AUTHOR

Edgar A. Bering, E<lt>trizor@gmail.comE<gt>


Copyright (C) 2007 by Edgar A. Bering

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.