From fdf7e6882733df8f024ef3ac6296fe3079ec3211 Mon Sep 17 00:00:00 2001 From: Patrick Donelan Date: Wed, 13 May 2009 08:59:50 +0000 Subject: [PATCH] Added Survey feedback template Added survey feedback template and method for returning the templated feedback for a given response Used this to clean up the default survey template, and updated the i18n and help --- .../root_import_survey_default-feedback.wgpkg | Bin 0 -> 1035 bytes .../root_import_survey_default-survey.wgpkg | Bin 1470 -> 1427 bytes docs/upgrades/upgrade_7.7.5-7.7.6.pl | 13 +- lib/WebGUI/Asset/Wobject/Survey.pm | 139 ++++++++++++------ lib/WebGUI/Help/Asset_Survey.pm | 61 +++++++- lib/WebGUI/i18n/English/Asset_Survey.pm | 79 +++++++--- t/Asset/Wobject/Survey/ExpressionEngine.t | 3 +- 7 files changed, 220 insertions(+), 75 deletions(-) create mode 100644 docs/upgrades/packages-7.7.6/root_import_survey_default-feedback.wgpkg diff --git a/docs/upgrades/packages-7.7.6/root_import_survey_default-feedback.wgpkg b/docs/upgrades/packages-7.7.6/root_import_survey_default-feedback.wgpkg new file mode 100644 index 0000000000000000000000000000000000000000..ed73251eb756932427245be0d11eb0b6ec38dedc GIT binary patch literal 1035 zcmV+m1oZnKiwFP!000001MOB(Z`(Ey_H%y)p%-sJ7fXs2#a>XLZJNbs?52&=3|+T? zHqSO2i4;i6j#Ko%m!c$7u@xlPY+w)JgDvQI_Z{!<`^3G*?w9MjVGuMLuIq(?YyZ(| zxed?rT|aOGzwI`V=e5JIfwar+S1J`2I<*8Vnc()?)!hBsRsZ*PpZYcszQ532a1_Kz zgcV$4rSNzb15?sLUG&%AFO6L)F7OnpuM)u%5Q>7?Xu@QX#sYL4@@ARsb@m zRG#DUjSi<1x(CS@48)}b(KEJcviICK9I=$33MY0o_{{rfqR-u+6CZzyCm)i|)Ml89 z$RsT|S1lT6=WoeW%wgFgFu`f0ewzT0kxtP%QF%%U0cJeC>icuS6<5n7FIA-yQ^C`u zN8S;taxdSymEARlBSPn|zOt_jp(CZceoZH6%=H5((C;%&{?lU$1jCAQhNEAa0%XFO zgw?+0OVoUw72*2A9Hsf|?})P^-W&@Aj2!EJns`U80%jdmht<-n9s@15HMaq&Xbe1k z6tdX1onsckK0WQU#coud`rlXjs8x2_P6A~!5L8`?=tS`N91Bf!GZmFdGE96s!)#hh zW6GdV0>^$eT=Uf^za18DtXVGyIL^oQ3Pyii_PSj&I^FKD5FNWc(}+GNbV75wI-cM5 zeb+tos?$tWl*c>H34~5I2vo4)Glg6-LW@CV#t}R!VpP~AZ)h^$N~4d>=&u(>t71BQ z0(e%y)JT$p6D^bTs+1Y+xS)6W2|Rzll0brmRwD!ZK&iUj(_#N?vv5?N@l4}#*}bQ7 zR2F42aVu!mJ{w!76Lva5=vQVzz?@300vVZe|C)wSBe1KXu%(tWzUZ+NF5rPRZ*K2~O+OP)BDfz+~KE+=)uVD2>QEbtD)gW%92YVv9^Ez%1{ zY;dPw5H9uy?0qLbY5z&zR&NF6_!s$Qm#iNzer)4H_Z;K70?!qAuD}y3@Dl-EK2rb^ F005&}``Z8j literal 0 HcmV?d00001 diff --git a/docs/upgrades/packages-7.7.6/root_import_survey_default-survey.wgpkg b/docs/upgrades/packages-7.7.6/root_import_survey_default-survey.wgpkg index c7df236cb956475057f3e440796f4a753a04597e..77153babdacdc75c65008bea6cadc3419ff06c31 100644 GIT binary patch literal 1427 zcmV;E1#J2siwFP!000001MOICZ`(Ey_UHZzLSNDWUHop>o|_?kNfR{9lE!HV%$q?= zjLk+O1(LGsuKn*jl9DOgl2fz^&;ikh#4(R|5ATlmJj#CM{-0W{)@`>dm0GRdZP(my zw0dfldc9F=v}^4~vsFR$db`%BAlP#MPa+i-04>H!#yBbsc-uN05*~dx`@7W9&$VFC z*4@vR{oLIDC^@?$sNlWRYPq^+ePGKE0h`T@`nS5BW(7eu@Bg{4`tRRA^t*`g?<1&! zr$`isSdlSS3j4E&FeN?IM}PhO#H>rj1)h@pSFzwR5sDIHXxwN|z98Tyc)rxOUeh!C z^+JfHdi5#h0#*;r9+rgRY8h^!GXA|dnS@l%NZ|G|viLw*z!%18%`M0!tYCx`W5~^SApKc44$215CGy8I`s5}>3akY$XqH=kd3ZBF#!K;8O zyQ|^cWwkX61B@7s$g`10gMmgqo@0U1109S!M1#_`gFzJ^jM#|Tjr1BxA|>T)AAIcN zAfoIK1_t_C58?yo-semS9!hW!!}_3V0@LetX91PagUcaRA<4YV8aX%0tPHB~Ww{d~ zeL-Uds4^d`QwG~>F{*C+3g}#anSw+KbjaApOego!R4(;w&WX`Xkn3meumsG;wxnYy z{sB7p=Y%OD7}lV0_;^oSAZxMrWbaTn)7U!R`{g&AW9?c$UrG;}p&H^Fl0#*2BrJr= zpa_3@M`X+y)af#rL{!1u1MnjSZLk4bfuG&5wZ$#4M+yK#@oj-EitYSvCiXogi+4od z3|Rth4i;kxwA9NGbD64h@q9oe&wvU{kPl??`s$?LH^Zpk zAEt7^nQQ!Sc|fnJB~q{6Xf;5w_ntm=MrJ@8e=jYyAv>9zMaom};g%Y^u3Mr~_XnPY z7EzA(@~~oPO?yz8rpWlsA6Dz2w8mzw*X#Cr?QSF22ZGG0=G~W> zWLgztEuUKUtQx{4TF&_5gdK4a*=*#31F2Z8lqn~JAQxF{2Y5^JZJsu(n<)*ax4a+L z8)(JDMPj2|X1EKvaa24&KsXk$(|IHJ$XiGdapxt)3dtm0-=otu9J#G_R~o`APT zkv7=LzvxR2!6wP(bV5P!P4?dkek=KBqz|fY>)`sjX9Qo$xdrsTg~BqQ(E+=u7L|r^ zWW7f1#i5+>_l7H__2Pgz^IKTG{Dd2nUL5E)M&DJ=Tpt&u`G3gY`O_NmcGHqDUo2yF zUNA@%o~AE>7l-)GS?A()blAMOIURoN9CH8k!a1Sxaw%atZjMtk$TNQMa)TJi(7Y-a z(V=<6UYq_f{+qpar`K^2fwVwCr107kcJ^73v+kmK#@_Uzqt>7F#nc(E#(s)Vzw&>5 h^z|DIc=X}yYbDVCYr(J$ z-QSjdzqk8Aa`uC$0{VWd$K1DpP^(Q1Zk`EPYP?HYn;-u-h|`QN>J>OaE6zYib_ zfg(v7V?{<-DLkGggee)I9{TI=M`m3rF7Sl-AEkn)L?}v(p@GpzV?h8Xdb-fI!CqkY z>xCFg_2Og71*{&KJuHjk1b`IQ`*q`(Uax{hRKgux45*4pfii7+Fv_g->+oSU2$5q! zQw6LFjO8h#&9xNOH?bl*(;wy}Q3f|;G{#H^_rhc@M>glgXe!9{6L(kwW+R)@5hVW* z9sYB|6cG$-QaFCNqb-oN*m<;bq%YIR0`L6ttBtXS*3ak4gBGj?_=b3_ERT%EkQtQV zk8g=gIfFc1WLF7QPSv z#Aiep9_9DPp3&K(!u}ghIuSS`qbtsDwguE!A#JtA#jRKMD+?$hF@Z@0*|Rs-660(f z)A0>7CqYyu7=os9O-1r>XE3D_&1oDXyAxq}tJ^wSUjAKlBnVpYOy6JoW{#Ocifb4} zSw?&X1>w;YG52aQ+kI;InK%61h zcl=#1So9pmDfHXiv#qN#8Uvb;=uM`!vM7wcn}iLGn@yBWiJxiSfyiftGbTWDG5ZwyhAXD|SbllSE6)#XXAXIgNtH^@bhGuJUa z$oKmX&}jii^rTL@6>Z z3$&c_`3ZZ;MPj4jIfqed6=IsZr!s@@R#|ynS4gaCapekr z*>hH8RliD5m2LFol4~=*i0W(kuFJiUHI+)EMAU4su=C!ipX~wzRl0E!Wkt}GyK=_g z>aJ4ElsojyZ_zTD!mo!p^C;3<3 z>AR%$>gfmeXXm8x7`LAvpI)-$$bnFKv5?Rm*W0OSn+a diff --git a/docs/upgrades/upgrade_7.7.5-7.7.6.pl b/docs/upgrades/upgrade_7.7.5-7.7.6.pl index e2abc490a..7fee6449c 100644 --- a/docs/upgrades/upgrade_7.7.5-7.7.6.pl +++ b/docs/upgrades/upgrade_7.7.5-7.7.6.pl @@ -36,6 +36,7 @@ addEuVatDbColumns( $session ); addShippingDrivers( $session ); addTransactionTaxColumns( $session ); addListingsCacheTimeoutToMatrix( $session ); +addSurveyFeedbackTemplateColumn( $session ); finish($session); @@ -116,7 +117,7 @@ sub addShippingDrivers { sub addEuVatDbColumns { my $session = shift; print "\tAdding columns for improved VAT number checking..." unless $quiet; - + $session->db->write( 'alter table tax_eu_vatNumbers add column viesErrorCode int(3) default NULL' ); print "Done\n" unless $quiet; @@ -135,6 +136,16 @@ sub addTransactionTaxColumns { } +#---------------------------------------------------------------------------- +sub addSurveyFeedbackTemplateColumn { + my $session = shift; + print "\tAdding columns for Survey Feedback Template..." unless $quiet; + $session->db->write("alter table Survey add column `feedbackTemplateId` char(22)"); + + print "Done\n" unless $quiet; + +} + # -------------- DO NOT EDIT BELOW THIS LINE -------------------------------- #---------------------------------------------------------------------------- diff --git a/lib/WebGUI/Asset/Wobject/Survey.pm b/lib/WebGUI/Asset/Wobject/Survey.pm index 448f70a79..9a7d5c623 100644 --- a/lib/WebGUI/Asset/Wobject/Survey.pm +++ b/lib/WebGUI/Asset/Wobject/Survey.pm @@ -168,6 +168,14 @@ sub definition { defaultValue => 'AjhlNO3wZvN5k4i4qioWcg', namespace => 'Survey/Edit', }, + feedbackTemplateId => { + tab => 'display', + fieldType => 'template', + defaultValue => 'nWNVoMLrMo059mDRmfOp9g', + label => $i18n->get('Feedback Template'), + hoverHelp => $i18n->get('Feedback Template help'), + namespace => 'Survey/Feedback', + }, overviewTemplateId => { tab => 'display', fieldType => 'template', @@ -1212,16 +1220,15 @@ sub view { my $self = shift; my $var = $self->getMenuVars; - my ($lastResponseCompleteCode, $lastResponseEndDate) = $self->getLastResponseDetails(); - - $var->{lastResponseCompleted} = $lastResponseCompleteCode == 1; - $var->{lastResponseEndDate} = WebGUI::DateTime->new($self->session, $lastResponseEndDate)->toUserTimeZone; - $var->{lastResponseTimedOut} = $lastResponseCompleteCode == 3; + my $responseDetails = $self->getResponseDetails(); + + # Add lastResponse template vars + for my $tv qw(endDate feedback complete restart timeout timeoutRestart) { + $var->{"lastResponse\u$tv"} = $responseDetails->{$tv}; + } $var->{maxResponsesSubmitted} = !$self->canTakeSurvey(); - my $out = $self->processTemplate( $var, undef, $self->{_viewTemplate} ); - - return $out; + return $self->processTemplate( $var, undef, $self->{_viewTemplate} ); } #------------------------------------------------------------------- @@ -1251,57 +1258,91 @@ sub getMenuVars { #------------------------------------------------------------------- -=head2 getLastResponseDetails ( ) +=head2 getResponseDetails ( [$responseId] ) -Gets the completeCode and endDate for the most recent response +Looks up details about a given response. + +=head3 responseId + +A specific responseId to use. If none given, the most recent completed response is used. =cut -sub getLastResponseDetails { +sub getResponseDetails { my $self = shift; - - my ($lastResponseCompleteCode, $lastResponseEndDate); - - my $userId = $self->session->user->userId(); - my $anonId - = $self->session->form->process('userid') - || $self->session->http->getCookies->{Survey2AnonId} - || undef; - $anonId && $self->session->http->setCookie( Survey2AnonId => $anonId ); - my $ip = $self->session->env->getIp; - my $string; - - if ( $anonId or $userId != 1 ) { - $string = 'userId'; - if ($anonId) { - $string = 'anonId'; - $userId = $anonId; - } - my $responseId - = $self->session->db->quickScalar( - "select Survey_responseId from Survey_response where $string = ? and assetId = ? and isComplete = 0", - [ $userId, $self->getId() ] ); - if ( !$responseId ) { - ($lastResponseCompleteCode, $lastResponseEndDate) = $self->session->db->quickArray( - "select isComplete, endDate from Survey_response where $string = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1", - [ $userId, $self->getId() ] - ); - } - - } - elsif ( $userId == 1 ) { - my $responseId = $self->session->db->quickScalar( - 'select Survey_responseId from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete = 0', - [ $userId, $ip, $self->getId() ] + my $responseId = shift; + + my ($lastResponseCompleteCode, $lastResponseEndDate, $rJSON); + + if ( $responseId ) { + ($lastResponseCompleteCode, $lastResponseEndDate, $rJSON) = $self->session->db->quickArray( + 'select isComplete, endDate, responseJSON from Survey_response where responseId = ?', [ $responseId ] ); - if ( !$responseId ) { - ($lastResponseCompleteCode, $lastResponseEndDate) = $self->session->db->quickArray( - 'select isComplete, endDate from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1', + } else { + my $userId = $self->session->user->userId(); + my $anonId + = $self->session->form->process('userid') + || $self->session->http->getCookies->{Survey2AnonId} + || undef; + $anonId && $self->session->http->setCookie( Survey2AnonId => $anonId ); + my $ip = $self->session->env->getIp; + my $string; + + if ( $anonId or $userId != 1 ) { + $string = 'userId'; + if ($anonId) { + $string = 'anonId'; + $userId = $anonId; + } + my $lastResponseId + = $self->session->db->quickScalar( + "select Survey_responseId from Survey_response where $string = ? and assetId = ? and isComplete = 0", + [ $userId, $self->getId() ] ); + if ( !$lastResponseId ) { + ($lastResponseCompleteCode, $lastResponseEndDate, $rJSON) = $self->session->db->quickArray( + "select isComplete, endDate, responseJSON from Survey_response where $string = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1", + [ $userId, $self->getId() ] + ); + } + } + elsif ( $userId == 1 ) { + my $lastResponseId = $self->session->db->quickScalar( + 'select Survey_responseId from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete = 0', [ $userId, $ip, $self->getId() ] ); + if ( !$lastResponseId ) { + ($lastResponseCompleteCode, $lastResponseEndDate, $rJSON) = $self->session->db->quickArray( + 'select isComplete, endDate, responseJSON from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1', + [ $userId, $ip, $self->getId() ] + ); + } } } - return ($lastResponseCompleteCode, $lastResponseEndDate); + + # Process the feedback text + my $feedback; + my $tags = {}; + if ($rJSON) { + $rJSON = from_json($rJSON) || {}; + + # All tags become template vars + $tags = $rJSON->{tags} || {}; + $tags->{complete} = $lastResponseCompleteCode == 1; + $tags->{restart} = $lastResponseCompleteCode == 2; + $tags->{timeout} = $lastResponseCompleteCode == 3; + $tags->{timeoutRestart} = $lastResponseCompleteCode == 4; + $tags->{endDate} = $lastResponseEndDate && WebGUI::DateTime->new($self->session, $lastResponseEndDate)->toUserTimeZone; + $feedback = $self->processTemplate($tags, $self->get('feedbackTemplateId') || 'nWNVoMLrMo059mDRmfOp9g'); + } + return { + completeCode => $lastResponseCompleteCode, + endDate => $tags->{endDate}, + feedback => $feedback, + complete => $tags->{complete}, + restart => $tags->{restart}, + timeout => $tags->{timeout}, + timeoutRestart => $tags->{timeoutRestart}, + }; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Help/Asset_Survey.pm b/lib/WebGUI/Help/Asset_Survey.pm index b68148f88..307bef875 100644 --- a/lib/WebGUI/Help/Asset_Survey.pm +++ b/lib/WebGUI/Help/Asset_Survey.pm @@ -15,9 +15,8 @@ our $HELP = { }, ], variables => [ - { 'name' => 'lastResponseCompleted help' }, - { 'name' => 'lastResponseTimedOut help' }, { 'name' => 'maxResponsesSubmitted' }, + { 'name' => 'lastResponseFeedback', description => 'lastResponseFeedback help' }, ], related => [ { tag => 'gradebook report template', @@ -35,6 +34,9 @@ our $HELP = { { tag => 'survey answer edit template', namespace => 'Asset_Survey' }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -98,6 +100,9 @@ our $HELP = { { tag => 'survey answer edit template', namespace => 'Asset_Survey' }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -166,7 +171,10 @@ our $HELP = { }, { tag => 'survey answer edit template', namespace => 'Asset_Survey' - }, + }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -211,6 +219,9 @@ our $HELP = { { tag => 'statistical overview report template', namespace => 'Asset_Survey' }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -255,6 +266,9 @@ our $HELP = { { tag => 'statistical overview report template', namespace => 'Asset_Survey' }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -294,6 +308,9 @@ our $HELP = { { tag => 'statistical overview report template', namespace => 'Asset_Survey' }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, ] }, @@ -366,7 +383,43 @@ our $HELP = { { 'name' => 'responseTemplateId' }, ], }, - + + 'survey feedback template' => { + title => 'survey feedback template variables title', + body => 'survey feedback template body', + isa => [], + fields => [], + variables => [ + { name => 'complete', description => 'response complete help' }, + { name => 'restart', description => 'response complete help' }, + { name => 'timeout', description => 'response timeout help' }, + { name => 'timeoutRestart', description => 'response timeout restart help' }, + { name => 'endDate', description => 'response endDate help' }, + ], + related => [ + { tag => 'survey template', + namespace => 'Asset_Survey' + }, + { tag => 'statistical overview report template', + namespace => 'Asset_Survey' + }, + { tag => 'gradebook report template', + namespace => 'Asset_Survey' + }, + { tag => 'survey section edit template', + namespace => 'Asset_Survey' + }, + { tag => 'survey question edit template', + namespace => 'Asset_Survey' + }, + { tag => 'survey answer edit template', + namespace => 'Asset_Survey' + }, + { tag => 'survey feedback template', + namespace => 'Asset_Survey' + }, + ] + }, }; 1; diff --git a/lib/WebGUI/i18n/English/Asset_Survey.pm b/lib/WebGUI/i18n/English/Asset_Survey.pm index eaee68574..350dead92 100644 --- a/lib/WebGUI/i18n/English/Asset_Survey.pm +++ b/lib/WebGUI/i18n/English/Asset_Survey.pm @@ -490,6 +490,17 @@ our $I18N = { message => q|The template to display the main page of the survey.|, lastUpdated => 0, }, + + 'Feedback Template' => { + message => q|Feedback Template|, + lastUpdated => 0, + }, + + 'Feedback Template help' => { + message => q|The template used to display response feedback.|, + lastUpdated => 0, + }, + 'do after timelimit label' => { message => q|Do After Time Limit:|, lastUpdated => 1224686319, @@ -925,32 +936,54 @@ directly inside the answer_loop for other types of questions.|, lastUpdated => 1078223096 }, - 'lastResponseCompleted' => { - message => q|You completed this Survey|, - lastUpdated => 1242180657, - }, - - 'lastResponseTimedOut' => { - message => q|Your last Survey response timed out|, + 'response complete' => { + message => q|Survey Response completed|, lastUpdated => 1242180657, }, - 'lastResponseCompleted help' => { - message => q|A boolean indicating whether the current user's last response was completed.|, - context => q|Description of a template variable for a template Help page.|, - lastUpdated => 0, + 'response complete help' => { + message => q|A boolean flag indicating whether the Survey Response completed|, + lastUpdated => 1242180657, }, - 'lastResponseEndDate help' => { - message => q|The date that the user's last response was completed.|, - context => q|Description of a template variable for a template Help page.|, - lastUpdated => 0, + 'response restart' => { + message => q|Survey Response restarted|, + lastUpdated => 1242180657, }, - - 'lastResponseTimedOut help' => { - message => q|A boolean indicating whether the current user's last response timed out.|, - context => q|Description of a template variable for a template Help page.|, - lastUpdated => 0, + + 'response restart help' => { + message => q|A boolean flag indicating whether the Survey Response restarted|, + lastUpdated => 1242180657, + }, + + 'response timeout' => { + message => q|Survey Response timed out|, + lastUpdated => 1242180657, + }, + + 'response timeout help' => { + message => q|A boolean flag indicating whether the Survey Response timed out|, + lastUpdated => 1242180657, + }, + + 'response timeout restart' => { + message => q|Survey Response restarted due to a timeout|, + lastUpdated => 1242180657, + }, + + 'response timeout restart help' => { + message => q|A boolean flag indicating whether the Survey Response restarted as a result of a timeout|, + lastUpdated => 1242180657, + }, + + 'response endDate help' => { + message => q|A localised date/time string indicating when the response ended|, + lastUpdated => 1242180657, + }, + + 'survey feedback template body' => { + message => q|All data tagged in survey expressions is also made available as template variables|, + lastUpdated => 1242180657, }, 'maxResponsesSubmitted' => { @@ -970,6 +1003,12 @@ directly inside the answer_loop for other types of questions.|, context => q|Description of a template variable for a template Help page.|, lastUpdated => 0, }, + + 'lastResponseFeedback help' => { + message => q|The templated response feedback text|, + context => q|Description of a template variable for a template Help page.|, + lastUpdated => 0, + }, 'user_canEditSurvey' => { message => q|A boolean indicating whether the current user can edit the survey.|, diff --git a/t/Asset/Wobject/Survey/ExpressionEngine.t b/t/Asset/Wobject/Survey/ExpressionEngine.t index b2fd409e3..2b5c603ae 100644 --- a/t/Asset/Wobject/Survey/ExpressionEngine.t +++ b/t/Asset/Wobject/Survey/ExpressionEngine.t @@ -22,7 +22,7 @@ my $session = WebGUI::Test->session; #---------------------------------------------------------------------------- # Tests -my $tests = 55; +my $tests = 56; plan tests => $tests + 1; #---------------------------------------------------------------------------- @@ -79,6 +79,7 @@ SKIP: { q{jump { answered(n) && !answered(X) } target}, # answered() works q{jump { value(multi) eq 'answer1, answer2' } target}, # multi-answer question stringifies in scalar context q{jump { (value(multi))[1] eq 'answer2' } target}, # multi-answer question returns list in list context + q{ sub mySub { return $_[0] + 2 } jump { mySub(1) == 3 } target } # expressions can define and use subs ); my @should_not_jump = (