You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(53) |
Feb
(56) |
Mar
|
Apr
|
May
(30) |
Jun
(78) |
Jul
(121) |
Aug
(155) |
Sep
(77) |
Oct
(61) |
Nov
(45) |
Dec
(94) |
2006 |
Jan
(116) |
Feb
(33) |
Mar
(11) |
Apr
(23) |
May
(60) |
Jun
(89) |
Jul
(130) |
Aug
(109) |
Sep
(124) |
Oct
(63) |
Nov
(82) |
Dec
(45) |
2007 |
Jan
(31) |
Feb
(35) |
Mar
(123) |
Apr
(36) |
May
(18) |
Jun
(134) |
Jul
(133) |
Aug
(241) |
Sep
(126) |
Oct
(31) |
Nov
(15) |
Dec
(5) |
2008 |
Jan
(11) |
Feb
(6) |
Mar
(16) |
Apr
(29) |
May
(43) |
Jun
(149) |
Jul
(27) |
Aug
(29) |
Sep
(37) |
Oct
(20) |
Nov
(4) |
Dec
(6) |
2009 |
Jan
(34) |
Feb
(30) |
Mar
(16) |
Apr
(6) |
May
(1) |
Jun
(32) |
Jul
(22) |
Aug
(7) |
Sep
(18) |
Oct
(50) |
Nov
(22) |
Dec
(8) |
2010 |
Jan
(17) |
Feb
(15) |
Mar
(10) |
Apr
(9) |
May
(67) |
Jun
(30) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
|
From: dpvc v. a. <we...@ma...> - 2007-08-26 19:17:15
|
Log Message: ----------- This is a rewrite of the Inequalities context that makes a number of improvements over the older version. First, the error messages are much better when students enter incorrect answers. Second, inequalities and intervals are now separate classes and so you can enter both types of notation and they will stringify and texify correctly, so there is no need for the stringifyAsInequalities flag any longer. Finally, there is a new Inequality() constructor that can be used to coerce Intervals, Sets, and Unions to become their corresponding inequalities, and vice versa, Interval(), Set() and Union() can be used to coerce an Inequality to be represented in its interval-style notation. This is not backaward compatible with the ealier version, but since that is only a couple of weeks old, I don't think it should be an issue, as very few problems will have been written for it in that time. Modified Files: -------------- pg/macros: contextInequalities.pl Revision Data ------------- Index: contextInequalities.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextInequalities.pl,v retrieving revision 1.6 retrieving revision 1.7 diff -Lmacros/contextInequalities.pl -Lmacros/contextInequalities.pl -u -r1.6 -r1.7 --- macros/contextInequalities.pl +++ macros/contextInequalities.pl @@ -15,24 +15,17 @@ # Usage: loadMacros("contextInequalities.pl"); # # Context("Inequalities"); - # $S1 = Formula("1 < x <= 4"); - # $S2 = Formula("(1,4]"); # either form is OK + # $S1 = Compute("1 < x <= 4"); + # $S2 = Inequality("(1,4]"); # force interval to be inequality # # Context("Inequalities-Only"); - # $S1 = Formula("1 < x <= 4"); - # $S2 = Formula("(1,4]"); # generates an error + # $S1 = Compute("1 < x <= 4"); + # $S2 = Inequality("(1,4]"); # generates an error # - # $S3 = Formula("x < -2 or x > 2"); # forms a Union - # $S4 = Formula("x = 1"); # forms a Set + # $S3 = Compute("x < -2 or x > 2"); # forms a Union + # $S4 = Compute("x = 1"); # forms a Set # - # You can set the "stringifyAsInequalities" flag to 1 to force - # output from the intervals, sets, and unions created in this - # context to be output as inequalities rather than their - # usual Inerval, Set or Union forms. - # - # Context("Inequalities")->flags->set(stringifyAsInequalities=>1); - # - # You can also set the "noneWord" flag to specify the string to + # You can set the "noneWord" flag to specify the string to # use when the inequalities specify the empty set. By default, # it is "NONE", but you can change it to other strings. Be sure # that you use a string that is defined in the Context, however, @@ -44,6 +37,24 @@ # # creates an empty set as a named constant and uses that name. # + # Inequalities and interval notation both can coexist side by + # side, but you may wish to convert from one to the other. + # Use Inequality() to convert from an Interval, Set or Union + # to an Inequality, and use Interval(), Set(), or Union() to + # convert from an Inequality object to one in interval notation. + # For example: + # + # $I0 = Compute("(1,2]"); # the interval (1,2] + # $I1 = Inequality($I); # the inequality 1 < x <= 2 + # + # $I0 = Compute("1 < x <= 2"); # the inequality 1 < x <= 2 + # $I1 = Interval($I0); # the interval (1,2] + # + # Note that ineqaulities and inervals can be compared and combined + # regardless of the format, so $I0 == $I1 is true in either example + # above. + # + ###################################################################### =cut @@ -61,16 +72,16 @@ '>' => {precedence => .5, associativity => 'left', type => 'bin', string => ' > ', class => 'Inequalities::BOP::inequality', eval => 'evalGreaterThan', combine => 1}, - '<=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' <= ', + '<=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' <= ', TeX => '\le ', class => 'Inequalities::BOP::inequality', eval => 'evalLessThanOrEqualTo', combine => 1}, - '>=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' >= ', + '>=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' >= ', TeX => '\ge ', class => 'Inequalities::BOP::inequality', eval => 'evalGreaterThanOrEqualTo', combine => 1}, '=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' = ', class => 'Inequalities::BOP::inequality', eval => 'evalEqualTo'}, - '!=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' != ', + '!=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' != ', TeX => '\ne ', class => 'Inequalities::BOP::inequality', eval => 'evalNotEqualTo'}, 'and' => {precedence => .45, associateivity => 'left', type => 'bin', string => " and ", @@ -79,33 +90,42 @@ 'or' => {precedence => .4, associateivity => 'left', type => 'bin', string => " or ", TeX => '\hbox{ or }', class => 'Inequalities::BOP::or'}, ); - $context->flags->set(stringifyAsInequalities => 0, noneWord => 'NONE'); - $context->{cmpDefaults}{Inequalities} = {reduceSets=>1}; - $context->{cmpDefaults}{Interval} = {reduceSets=>1}; - $context->{cmpDefaults}{Union} = {reduceSets=>1}; - $context->{cmpDefaults}{Set} = {reduceSets=>1}; + $context->operators->set( + '+' => {class => "Inequalities::BOP::add"}, + '-' => {class => "Inequalities::BOP::subtract"}, + ); + $context->parens->set("(" => {type => "List", formIntervla => ']'}); # trap these later + $context->parens->set("[" => {type => "List", formIntervla => ')'}); # trap these later $context->strings->remove("NONE"); $context->constants->add(NONE=>Value::Set->new()); + $context->flags->set(noneWord => 'NONE'); $context->{parser}{Variable} = "Inequalities::Variable"; - $context->{value}{Interval} = "Inequalities::Interval"; - $context->{value}{Union} = "Inequalities::Union"; - $context->{value}{Set} = "Inequalities::Set"; + $context->{value}{'Interval()'} = "Inequalities::MakeInterval"; + $context->{value}{Inequality} = "Inequalities::Inequality"; + $context->{value}{InequalityInterval} = "Inequalities::Interval"; + $context->{value}{InequalityUnion} = "Inequalities::Union"; + $context->{value}{InequalitySet} = "Inequalities::Set"; + $context->{value}{List} = "Inequalities::List"; + $context->{precedence}{Inequality} = $context->{precedence}{special}; + $context->lists->set(List => {class => 'Inequalities::List::List'}); # - # Disable interval notation in Context("Inequalities-Only"); + # Disable interval notation in "Inequalities-Only" context # $context = $main::context{"Inequalities-Only"} = $context->copy; - $context->parens->remove('(','[','{'); - $context->parens->redefine('(',from=>"Numeric"); - $context->parens->redefine('[',from=>"Numeric"); - $context->parens->redefine('{',from=>"Numeric"); - $context->parens->set( - '(' => {formInterval=>0}, - '[' => {formInterval=>0} + $context->lists->set( + Interval => {class => 'Inequalities::List::notAllowed'}, + Set => {class => 'Inequalities::List::notAllowed'}, + Union => {class => 'Inequalities::List::notAllowed'}, ); - $context->lists->set(List => {class => 'Inequalities::List::List'}); - $context->operators->remove('U'); + $context->operators->set('U' => {class => 'Inequalities::BOP::union'}); $context->constants->remove('R'); + + # + # Define the Inequality() constructor + # + main::PG_restricted_eval('sub Inequality {Value->Package("Inequality")->new(@_)}'); + return; } @@ -121,7 +141,7 @@ # # Check that the inequality is formed between a variable and a number, -# or between a number and another compatable inequality. Otherwise, +# or between a number and another compatible inequality. Otherwise, # give an error. # # varPos and numPos tell which of lop or rop is the variable and which @@ -129,7 +149,7 @@ # sub _check { my $self = shift; - $self->{type} = Value::Type("Interval",2); + $self->{type} = $Value::Type{interval}; $self->{isInequality} = 1; ($self->{varPos},$self->{numPos}) = ($self->{lop}->class eq 'Variable' || $self->{lop}{isInequality} ? ('lop','rop') : ('rop','lop')); @@ -162,7 +182,7 @@ sub _eval { my $self = shift; my ($a,$b) = @_; my $eval = $self->{def}{eval}; - my $I = $self->$eval(@_); + my $I = $self->Package("Inequality")->new($self->context,$self->$eval(@_),$self->{varName}); return $I->intersect($a) if Value::isValue($a) && $a->type eq 'Interval'; return $I->intersect($b) if Value::isValue($b) && $b->type eq 'Interval'; return $I; @@ -252,10 +272,11 @@ sub _check { my $self = shift; - $self->Error("The operands of '%s' must be Intervals, Sets or Unions") - unless $self->{lop}->isSetOfReals && $self->{rop}->isSetOfReals; + $self->Error("The operands of '%s' must be inequalities",$self->{bop}) + unless $self->{lop}{isInequality} && $self->{rop}{isInequality}; $self->{type} = Value::Type("Interval",2); $self->{varName} = $self->{lop}{varName} || $self->{rop}{varName}; + $self->{isInequality} = 1; } sub _eval {$_[1]->intersect($_[2])} @@ -269,10 +290,11 @@ sub _check { my $self = shift; - $self->Error("The operands of '%s' must be Intervals, Sets or Unions") - unless $self->{lop}->isSetOfReals && $self->{rop}->isSetOfReals; + $self->Error("The operands of '%s' must be inequalities",$self->{bop}) + unless $self->{lop}{isInequality} && $self->{rop}{isInequality}; $self->{type} = Value::Type("Interval",2); $self->{varName} = $self->{lop}{varName} || $self->{rop}{varName}; + $self->{isInequality} = 1; } sub _eval {$_[1] + $_[2]} @@ -333,45 +355,171 @@ ################################################## # -# For the Inequalities-Only context, we make lists -# that report errors, so that students MUST produce -# their intervals via inequalities. +# Give an error when U is used. # -package Inequalities::List::List; -our @ISA = ("Parser::List::List"); +package Inequalities::BOP::union; +our @ISA = ("Parser::BOP::union"); sub _check { my $self = shift; + $self->Error("You can't take unions of inequalities") + if $self->{lop}{isInequality} || $self->{rop}{isInequality}; $self->SUPER::_check(@_); - $self->Error("You are not allowed to use intervals or sets in this context") if $self->{open}; + $self->Error("Unions are not allowed in this context"); } ################################################## # -# Override the string and TeX methods -# so that we can strinfigy as inequalities -# rather than intervals. +# Don't allow sums and differences of inequalities # -package Inequalities::Interval; -our @ISA = ("Value::Interval"); +package Inequalities::BOP::add; +our @ISA = ("Parser::BOP::add"); -sub new { - my $self = shift; $self = $self->SUPER::new(@_); - $self->{isValue} = 1; - return $self; +sub _check { + my $self = shift; + $self->SUPER::_check(@_); + $self->Error("Can't add inequalities (do you mean to use 'or'?)") + if $self->{lop}{isInequality} || $self->{rop}{isInequality}; } -sub make { - my $self = shift; $self = $self->SUPER::make(@_); - $self->{isValue} = 1; - return $self; +################################################## +# +# Don't allow sums and differences of inequalities +# +package Inequalities::BOP::subtract; +our @ISA = ("Parser::BOP::subtract"); + +sub _check { + my $self = shift; + $self->SUPER::_check(@_); + $self->Error("Can't subtract inequalities") + if $self->{lop}{isInequality} || $self->{rop}{isInequality}; +} + +################################################## +# +# For the Inequalities-Only context, report +# an error for Intervals, Sets or Union notation. +# +package Inequalities::List::notAllowed; +our @ISA = ("Parser::List::List"); + +sub _check {(shift)->Error("You are not allowed to use intervals or sets in this context")} + + +################################################## +################################################## +# +# Subclasses of the Interval, Set, and Union classes +# that stringify as inequalities +# + +# +# Some common routines to all three classes +# +package Inequalities::common; + +# +# Turn the object back into its usual Value version +# +sub demote { + my $self = shift; my $context = $self->context; + my $other = shift; $other = $self unless defined $other; + return $other unless Value::classMatch($other,"Inequality"); + $context->Package($other->type)->make($context,$other->makeData); +} + +# +# Needed to get Interval data in the right order for make(), +# and demote all the items in a Union +# +sub makeData {(shift)->value} + +# +# Recursively mark Intervals and Sets in a Union as Inequalities +# +sub updateParts {} + +# +# Demote the operands to normal Value objects and +# perform the action, then remake the result into +# an Inequality again. +# +sub apply { + my $self = shift; my $context = $self->context; + my $method = shift; my $other = shift; + $context->Package("Inequality")->new($context, + $self->demote->$method($self->demote($other),@_), + $self->{varName}); +} + +sub add {(shift)->apply("add",@_)} +sub sub {(shift)->apply("sub",@_)} +sub reduce {(shift)->apply("reduce",@_)} +sub intersect {(shift)->apply("intersect",@_)} + +# +# The name to use for error messages in answer checkers +# +sub class {"Inequality"} +sub cmp_class {"an Inequality"} +sub showClass {"an Inequality"} +sub typeRef { + my $self = shift; + return Value::Type($self->type, $self->length, $Value::Type{number}); +} + +# +# Get the precedence based on the type rather than the class. +# +sub precedence { + my $self = shift; my $precedence = $self->context->{precedence}; + return $precedence->{$self->type}-$precedence->{Interval}+$precedence->{$self->class}; +} + +# +# Produce better error messages for inequalities +# +sub cmp_checkUnionReduce { + my $self = shift; my $student = shift; my $ans = shift; my $nth = shift || ''; + if (Value::classMatch($student,"Inequality")) { + return unless $ans->{studentsMustReduceUnions} && + $ans->{showUnionReduceWarnings} && + !$ans->{isPreview} && !Value::isFormula($student); + my ($result,$error) = $student->isReduced; + return unless $error; + return { + "overlaps" => "Your$nth answer contains overlapping inequalities", + "overlaps in sets" => "Your$nth answer contains equalities that are already included elsewhere", + "uncombined intervals" => "Your$nth answer can be simplified by combining some inequalities", + # shouldn't get the following ones from inequalities + "uncombined sets" => "", + "repeated elements in set" => "", + "repeated elements" => "", + }->{$error}; + } else { + return unless Value::can($student,"isReduced"); + return Value::cmp_checkUnionReduce($self,$student,$ans,$nth,@_) + } +} + + +################################################## + +package Inequalities::Interval; +our @ISA = ("Inequalities::common", "Value::Interval"); + +sub type {"Interval"} + +sub makeData { + my ($a,$b,$open,$close) = (shift)->value; + return ($open,$a,$b,$close); } sub string { my $self = shift; - return $self->SUPER::string(@_) unless $self->getFlag('stringifyAsInequalities'); my ($a,$b,$open,$close) = $self->value; - my $x = ($self->context->variables->names)[0]; + my $x = $self->{varName} || ($self->context->variables->names)[0]; $x = $context->{variables}{$x}{string} if defined $context->{variables}{$x}{string}; my $left = ($open eq '(' ? ' < ' : ' <= '); my $right = ($close eq ')' ? ' < ' : ' <= '); @@ -385,10 +533,9 @@ sub TeX { my $self = shift; - return $self->SUPER::TeX(@_) unless $self->getFlag('stringifyAsInequalities'); my ($a,$b,$open,$close) = $self->value; my $context = $self->context; - my $x = ($context->variables->names)[0]; + my $x = $self->{varName} || ($context->variables->names)[0]; $x = $context->{variables}{$x}{TeX} if defined $context->{variables}{$x}{TeX}; $x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/; my $left = ($open eq '(' ? ' < ' : ' <= '); @@ -401,32 +548,46 @@ return $inequality; } -sub cmp_class {"an Inequality"} - ################################################## -# -# Override the string and TeX methods -# so that we can strinfigy as inequalities -# rather than unions. -# + package Inequalities::Union; -our @ISA = ("Value::Union"); +our @ISA = ("Inequalities::common", "Value::Union"); -sub new { - my $self = shift; $self = $self->SUPER::new(@_); - $self->{isValue} = 1; - return $self; +sub type {"Union"} + +# +# Mark all the parts of the union as inequalities +# +sub updateParts { + my $self = shift; + foreach my $I (@{$self->{data}}) { + $I->{varName} = $self->{varName}; + $I->{reduceSets} = $I->{"is".$I->type} = 1; + bless $I, $self->Package("Inequality".$I->type); + $I->updateParts; + } } +# +# Update the intervals and sets when a new union is made +# sub make { - my $self = shift; $self = $self->SUPER::make(@_); - $self->{isValue} = 1; + my $self = (shift)->SUPER::make(@_); + $self->updateParts; return $self; } +# +# Demote all the items in the union +# +sub makeData { + my $self = shift; my @U = (); + foreach my $I (@{$self->{data}}) {push(@U,$I->demote)} + return @U; +} + sub string { my $self = shift; - return $self->SUPER::string(@_) unless $self->getFlag('stringifyAsInequality'); my $equation = shift; shift; shift; my $prec = shift; my $op = ($equation->{context} || $self->context)->{operators}{'or'}; my @intervals = (); @@ -435,49 +596,31 @@ push(@intervals,$x->string($equation)) } my $string = join($op->{string} || ' or ',@intervals); - $string = '('.$string.')' if $prec > ($op->{precedence} || 1.5); + $string = '('.$string.')' if defined($prec) && $prec > ($op->{precedence} || 1.5); return $string; } sub TeX { my $self = shift; - return $self->SUPER::TeX(@_) unless $self->getFlag('stringifyAsInequality'); my $equation = shift; shift; shift; my $prec = shift; my $op = ($equation->{context} || $self->context)->{operators}{'or'}; my @intervals = (); foreach my $x (@{$self->data}) {push(@intervals,$x->TeX($equation))} - my $TeX = join($op->{TeX} || $op->{string} || ' or ',@intervals); - $TeX = '\left('.$TeX.'\right)' if $prec > ($op->{precedence} || 1.5); + my $TeX = join($op->{TeX} || $op->{string} || '\hbox{ or }',@intervals); + $TeX = '\left('.$TeX.'\right)' if defined($prec) && $prec > ($op->{precedence} || 1.5); return $TeX; } -sub cmp_class {"an Inequality"} - ################################################## -# -# Override the string and TeX methods -# so that we can strinfigy as inequalities -# rather than sets. -# + package Inequalities::Set; -our @ISA = ("Value::Set"); +our @ISA = ("Inequalities::common", "Value::Set"); -sub new { - my $self = shift; $self = $self->SUPER::new(@_); - $self->{isValue} = 1; - return $self; -} - -sub make { - my $self = shift; $self = $self->SUPER::make(@_); - $self->{isValue} = 1; - return $self; -} +sub type {"Set"} sub string { my $self = shift; my $equation = shift; - return $self->SUPER::string($equation,@_) unless $self->getFlag('stringifyAsInequality'); - my $x = ($self->context->variables->names)[0]; + my $x = $self->{varName} || ($self->context->variables->names)[0]; $x = $context->{variables}{$x}{string} if defined $context->{variables}{$x}{string}; my @coords = (); foreach my $a (@{$self->data}) { @@ -494,8 +637,7 @@ sub TeX { my $self = shift; my $equation = shift; - return $self->SUPER::TeX($equation,@_) unless $self->getFlag('stringifyAsInequality'); - my $x = ($self->context->variables->names)[0]; + my $x = $self->{varName} || ($self->context->variables->names)[0]; $x = $context->{variables}{$x}{TeX} if defined $context->{variables}{$x}{TeX}; $x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/; my @coords = (); @@ -508,10 +650,82 @@ } } return '\hbox{'.$self->getFlag('noneWord').'}' unless scalar(@coords); - return join(" or ",@coords); + return join('\hbox{ or }',@coords); } -sub cmp_class {"an Equality"} +################################################## +# +# A class for making inequalities by hand +# +package Inequalities::Inequality; +our @ISA = ('Value'); + +sub new { + my $self = shift; my $class = ref($self) || $self; + my $context = (Value::isContext($_[0]) ? shift : $self->context); + my $S = shift; my $x = shift; + $S = Value::makeValue($S,context=>$context); + if (Value::classMatch($S,"Inequality")) { + if (defined($x)) {$S->{varName} = $x; $S->updateParts} + return $S; + } + $x = ($self->context->variables->names)[0] unless $x; + $S = bless $S->inContext($context), $self->Package("Inequality".$S->type); + $S->{varName} = $x; $S->{reduceSets} = $S->{"is".$S->Type} = 1; + $S->updateParts; + return $S; +} + +################################################## +# +# Allow Interval() to coerce types to Value::Interval +# +package Inequalities::MakeInterval; +our @ISA = ("Value::Interval"); + +sub new { + my $self = shift; + $self = $self->SUPER::new(@_); + $self = $self->demote if $self->classMatch("Inequality"); + return $self; +} + +################################################## +# +# Mark this as a list of inequalities (if it is) +# +package Inequalities::List; +our @ISA = ("Value::List"); + +sub new { + my $self = (shift)->SUPER::new(@_); + return $self unless $self->{type} =~ m/^(unknown|Interval|Set|Union)$/; + foreach my $x (@{$self->{data}}) {return $self unless Value::classMatch($x,'Inequality')} + $self->{type} = 'Inequality'; + return $self; +} + +package Inequalities::List::List; +our @ISA = ("Parser::List::List"); + +sub _check { + my $self = shift; $self->SUPER::_check(@_); + if ($self->canBeInUnion) { + # + # Convert lists that look like intervals into intervals + # and then check if they are OK. + # + bless $self, $self->context->{lists}{Interval}{class}; + $self->{type} = $Value::Type{interval}; + $self->{parens} = $self->context->{parens}{interval}; + $self->_check; + } else { + my $entryType = $self->typeRef->{entryType}; + return unless $entryType->{name} =~ m/^(unknown|Interval|Set|Union)$/; + foreach my $x (@{$self->{coords}}) {return unless $x->{isInequality}}; + $entryType->{name} = "Inequality"; + } +} ################################################## |
From: dpvc v. a. <we...@ma...> - 2007-08-26 19:11:13
|
Log Message: ----------- Improve error messages for unreduced unions. Modified Files: -------------- pg/lib/Value: AnswerChecker.pm Union.pm Revision Data ------------- Index: AnswerChecker.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/AnswerChecker.pm,v retrieving revision 1.107 retrieving revision 1.108 diff -Llib/Value/AnswerChecker.pm -Llib/Value/AnswerChecker.pm -u -r1.107 -r1.108 --- lib/Value/AnswerChecker.pm +++ lib/Value/AnswerChecker.pm @@ -321,7 +321,8 @@ my ($result,$error) = $student->isReduced; return unless $error; return { - overlaps => "Your$nth union can be written without overlaps", + "overlaps" => "Your$nth union contains overlapping intervals", + "overlaps in sets" => "Your$nth union contains sets and intervals that overlap", "uncombined intervals" => "Your$nth union can be simplified by combining intervals", "uncombined sets" => "Your$nth union can be simplified by combining some sets", "repeated elements in set" => "Your$nth union contains sets with repeated elements", Index: Union.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Union.pm,v retrieving revision 1.41 retrieving revision 1.42 diff -Llib/Value/Union.pm -Llib/Value/Union.pm -u -r1.41 -r1.42 --- lib/Value/Union.pm +++ lib/Value/Union.pm @@ -250,7 +250,7 @@ if ($x->intersects($y)) {$error = "overlaps"; last} if (($x + $y)->reduce->type ne 'Union') {$error = "uncombined intervals"; last} } - $error = "overlaps" if !$error && $S->intersects($U); + $error = "overlaps in sets" if !$error && $S->intersects($U); $error = "uncombined sets" if !$error && $Sn > 1 && !$self->getFlag('reduceSets'); $error = "repeated elements in set" if !$error && !$S->isReduced; return $error eq "" unless $error && wantarray; |
From: dpvc v. a. <we...@ma...> - 2007-08-26 18:59:20
|
Log Message: ----------- Only try to form intervals from lists that could be intervals when they are of length 2. Modified Files: -------------- pg/lib/Parser: List.pm Revision Data ------------- Index: List.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/List.pm,v retrieving revision 1.22 retrieving revision 1.23 diff -Llib/Parser/List.pm -Llib/Parser/List.pm -u -r1.22 -r1.23 --- lib/Parser/List.pm +++ lib/Parser/List.pm @@ -28,10 +28,9 @@ my $context = $equation->{context}; my $parens = $context->{parens}; - if ($paren && $close && $paren->{formInterval}) { + if ($paren && $close && $paren->{formInterval} && scalar(@{$coords}) == 2) { $paren = $parens->{interval} - if ($paren->{close} ne $close || (scalar(@{$coords}) == 2 && - ($coords->[0]->{isInfinite} || $coords->[1]->{isInfinite}))); + if $paren->{close} ne $close || $coords->[0]->{isInfinite} || $coords->[1]->{isInfinite}; } my $type = Value::Type($paren->{type},scalar(@{$coords}),$entryType, list => 1, formMatrix => $paren->{formMatrix}); |
From: dpvc v. a. <we...@ma...> - 2007-08-26 12:19:57
|
Log Message: ----------- Allow object classes to override their own precedence values. Modified Files: -------------- pg/lib: Value.pm Revision Data ------------- Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.89 retrieving revision 1.90 diff -Llib/Value.pm -Llib/Value.pm -u -r1.89 -r1.90 --- lib/Value.pm +++ lib/Value.pm @@ -669,11 +669,12 @@ sub promotePrecedence { my $self = shift; my $other = shift; my $context = $self->context; return 0 unless Value::isValue($other); - my $sprec = $context->{precedence}{class($self)}; - my $oprec = $context->{precedence}{class($other)}; + my $sprec = $self->precedence; my $oprec = $other->precedence; return (defined($sprec) && defined($oprec) && $sprec < $oprec); } +sub precedence {my $self = shift; return $self->context->{precedence}{$self->class}} + sub promote { my $self = shift; my $class = ref($self) || $self; my $context = (Value::isContext($_[0]) ? shift : $self->context); |
From: dpvc v. a. <we...@ma...> - 2007-08-26 12:19:10
|
Log Message: ----------- Had the test reversed in isReduced when returning a boolean rather than an array (Argh!) Modified Files: -------------- pg/lib/Value: Union.pm Revision Data ------------- Index: Union.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Union.pm,v retrieving revision 1.40 retrieving revision 1.41 diff -Llib/Value/Union.pm -Llib/Value/Union.pm -u -r1.40 -r1.41 --- lib/Value/Union.pm +++ lib/Value/Union.pm @@ -253,7 +253,7 @@ $error = "overlaps" if !$error && $S->intersects($U); $error = "uncombined sets" if !$error && $Sn > 1 && !$self->getFlag('reduceSets'); $error = "repeated elements in set" if !$error && !$S->isReduced; - return $error ne "" unless $error && wantarray; + return $error eq "" unless $error && wantarray; return (0,$error); } |
From: dpvc v. a. <we...@ma...> - 2007-08-26 12:02:23
|
Log Message: ----------- Make sure the constructor creates the interval in the correct context. Modified Files: -------------- pg/lib/Value: Interval.pm Revision Data ------------- Index: Interval.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Interval.pm,v retrieving revision 1.41 retrieving revision 1.42 diff -Llib/Value/Interval.pm -Llib/Value/Interval.pm -u -r1.41 -r1.42 --- lib/Value/Interval.pm +++ lib/Value/Interval.pm @@ -22,7 +22,7 @@ return $x if $x->type eq 'Interval'; Value::Error("Formula does not return an Interval"); } - return $self->promote($x); + return $self->promote($context,$x); } my @params = @_; Value::Error("Interval can't be empty") unless scalar(@params) > 0; |
From: dpvc v. a. <we...@ma...> - 2007-08-26 03:09:23
|
Log Message: ----------- Allow Interval constructor to handle more situations. Modified Files: -------------- pg/lib/Value: Interval.pm Revision Data ------------- Index: Interval.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Interval.pm,v retrieving revision 1.40 retrieving revision 1.41 diff -Llib/Value/Interval.pm -Llib/Value/Interval.pm -u -r1.40 -r1.41 --- lib/Value/Interval.pm +++ lib/Value/Interval.pm @@ -16,7 +16,7 @@ sub new { my $self = shift; my $class = ref($self) || $self; my $context = (Value::isContext($_[0]) ? shift : $self->context); - if (scalar(@_) == 1 && (!ref($_[0]) || ref($_[0]) eq 'ARRAY')) { + if (scalar(@_) == 1) { my $x = Value::makeValue($_[0],context=>$context); if (Value::isFormula($x)) { return $x if $x->type eq 'Interval'; @@ -151,7 +151,7 @@ my $x = (scalar(@_) ? shift : $self); return $self->new($context,$x,@_) if scalar(@_) > 0; $x = Value::makeValue($x,context=>$context); - return $x if $x->isSetOfReals; + return $x->inContext($context) if $x->isSetOfReals; return $context->Package("Set")->new($context,$x) if Value::isReal($x); my $open = $x->{open}; $open = '(' unless defined($open); my $close = $x->{close}; $close = ')' unless defined($close); |
From: dpvc v. a. <we...@ma...> - 2007-08-26 03:08:00
|
Log Message: ----------- Minor change (don't need to check for isValue since we are already assuming that in the previous line). Modified Files: -------------- pg/lib/Value: Union.pm Revision Data ------------- Index: Union.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Union.pm,v retrieving revision 1.39 retrieving revision 1.40 diff -Llib/Value/Union.pm -Llib/Value/Union.pm -u -r1.39 -r1.40 --- lib/Value/Union.pm +++ lib/Value/Union.pm @@ -104,7 +104,7 @@ return $context->Package("Set")->new($context,$x,@_) if scalar(@_) > 0 || Value::isReal($x); return $x->inContext($context) if ref($x) eq $class; $x = $context->Package("Interval")->promote($context,$x) if $x->canBeInUnion; - return $self->make($context,$x) if Value::isValue($x) && $x->isSetOfReals; + return $self->make($context,$x) if $x->isSetOfReals; Value::Error("Can't convert %s to an Interval, Set or Union",Value::showClass($x)); } |
From: dpvc v. a. <we...@ma...> - 2007-08-26 03:06:55
|
Log Message: ----------- Add a predefined type structure for intervals. Modified Files: -------------- pg/lib: Value.pm Revision Data ------------- Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.88 retrieving revision 1.89 diff -Llib/Value.pm -Llib/Value.pm -u -r1.88 -r1.89 --- lib/Value.pm +++ lib/Value.pm @@ -591,6 +591,7 @@ complex => Value::Type('Number',2), string => Value::Type('String',1), infinity => Value::Type('Infinity',1), + interval => Value::Type('Interval',2), unknown => Value::Type('unknown',0,undef,list => 1) ); |
From: Sam H. v. a. <we...@ma...> - 2007-08-26 01:28:22
|
Log Message: ----------- updated for 2.4.1 Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib: WeBWorK.pm Revision Data ------------- Index: WeBWorK.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK.pm,v retrieving revision 1.94.4.4 retrieving revision 1.94.4.5 diff -Llib/WeBWorK.pm -Llib/WeBWorK.pm -u -r1.94.4.4 -r1.94.4.5 --- lib/WeBWorK.pm +++ lib/WeBWorK.pm @@ -34,7 +34,7 @@ =cut -BEGIN { $main::VERSION = "2.4.0"; } +BEGIN { $main::VERSION = "2.4.1"; } use strict; use warnings; |
From: Sam H. v. a. <we...@ma...> - 2007-08-26 01:27:02
|
Log Message: ----------- updated for 2.4.1 Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2: LICENSE Revision Data ------------- Index: LICENSE =================================================================== RCS file: /webwork/cvs/system/webwork2/LICENSE,v retrieving revision 1.6.4.2 retrieving revision 1.6.4.3 diff -LLICENSE -LLICENSE -u -r1.6.4.2 -r1.6.4.3 --- LICENSE +++ LICENSE @@ -1,7 +1,7 @@ WeBWorK Online Homework Delivery System - Version 2.4.0 + Version 2.4.1 Copyright 2000-2007, The WeBWorK Project All rights reserved. |
From: Sam H. v. a. <we...@ma...> - 2007-08-26 01:23:33
|
Log Message: ----------- updated for 2.4.1 Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2: README Revision Data ------------- Index: README =================================================================== RCS file: /webwork/cvs/system/webwork2/README,v retrieving revision 1.17.4.2 retrieving revision 1.17.4.3 diff -LREADME -LREADME -u -r1.17.4.2 -r1.17.4.3 --- README +++ README @@ -1,6 +1,156 @@ WeBWorK Online Homework Delivery System - Version 2.4.0 + Version 2.4.1 Copyright 2000-2007, The WeBWorK Project All rights reserved. + +Details +------- + +Release date: 25-August-2007 +CVS tag: rel-2-4-1 +CVS branch: rel-2-4-dev + +Changes since 2.4.0 +------------------- + +* Fixed a "Duplicate entry" error that occurred when WeBWorK attempted to assign + a set to a user to whom it was already assigned, for example with the "Assign + Set to All Users" button. (Bug #1293) + +* Fixed a problem that occurred when viewing the set details for a set that had + not been assigned to any users. + +* Added the ability to unarchive .tar.gz and .tar files to the File Manager. + +* Worked around an IE bug in the File Manager where pressing return submits a + form but does not set the submit button's value properly in some + circumstances. + +* Fixed a problem where the "over time: closed." status message would appear in + incorrect circumstances in the problem set list. + +* Improved handling of textbook chapters and sections in the NPL-update script. + +* Improved handling in the NPL-update script for problems which are tagged to a + chapter, but not to a particular section in the chapter. + +* Show the numbers for textbook chapters and sections in the Library Browser. + +* Improve speed of browsing the National Problem Library in the Library Browser. + +* Ignore .svn directories when browsing file-based problem libraries in the + Library browser. + +* Extended the set definition file format to support commas in the source_file, + value, and max_attempts fields. Literal commas and backslashes are backslash- + escaped. + +Installation & Upgrade +---------------------- + +Comprehensive installation and upgrade instructions are located at: +http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/InstallationManualV2pt4 + +Read the sections below for specific information about upgrading from various +versions of WeBWorK. + +Upgrading from 2.4.0 +-------------------- + +Before beginning, back up your WeBWorK database and course directories. + +To update WeBWorK to exactly 2.4.1, use the following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-1 + +To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and +includes bug fixes and new features before they are officially released, use the +following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-dev + +If you are using the National Problem Library, re-run bin/NPL-update to update +the database format to the latest version. + +No database changes occurred between 2.4.0 and 2.4.1, so running bin/wwdb_upgrade +is not necessary. No configuration file changes occurred between + +Upgrading from 2.3.x +-------------------- + +Before beginning, back up your WeBWorK database and course directories. + +To update WeBWorK to exactly 2.4.1, use the following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-1 + +To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and +includes bug fixes and new features before they are officially released, use the +following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-dev + +Merge changes from global.conf.dist, database.conf.dist, and +webwork.apache-config (if you are using Apache 1) or webwork.apache2-config (if +you are using Apache 2) into your configuration files. + +Run bin/wwdb_upgrade -v to upgrade your database. If you receive errors about +modelCourse it is OK to go on -- modelCourse is not a real course. + +If you are using the National Problem Library, the loadDB2 script in the +database_problems directory has been replaced with a new bin/NPL-update script +in the main webwork2 distribution. The problem library metadata is now stored +within the main webwork database. Run bin/NPL-update to load the problem +metadata into the its new location. It is safe to remove the separate +ProblemLibrary database. + +Upgrading from 2.2.x +-------------------- + +Make sure you are using the sql_single database layout for all the courses you +wish to continue to use. After you upgrade, courses using other database +layouts will be inaccessible. Move non-sql_single courses out of your courses +directory. + +The standard directory layout of WeBWorK has changed since 2.2.x. We now suggest +that you place the webwork2 directory, as well as the pg, courses, and +libraries, directories in /opt/webwork rather than in /opt. + +To update WeBWorK to exactly 2.4.1, use the following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-1 + +To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and +includes bug fixes and new features before they are officially released, use the +following commands: + +cd /opt/webwork/webwork2 +cvs -q up -dP -rrel-2-4-dev + +Merge changes from global.conf.dist, database.conf.dist, and +webwork.apache-config into your configuration files. + +Run bin/wwdb_check -v to verify that your database is up-to-date for version +2.3.0 (the first version that included automated database upgrades). Then run +bin/wwdb_upgrade -v to upgrade to bring your database up-to-date for version +2.4.1. + +Getting help +------------ + +The best place to get support is in the WeBWorK discussion forums located at: +http://webwork.maa.org/moodle/course/view.php?id=2 + +To report bugs: +http://bugs.webwork.rochester.edu/ + +Lots of WeBWorK documentation: +http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKDocs + |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:31:57
|
Log Message: ----------- backport (sh002i): Extended the set definition file format to support commas in the source_file field (as well was the value and max_attempts fields). Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: ProblemSetList.pm Revision Data ------------- Index: ProblemSetList.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm,v retrieving revision 1.101.2.3 retrieving revision 1.101.2.4 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -u -r1.101.2.3 -r1.101.2.4 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm @@ -1718,7 +1718,23 @@ $line =~ s/(#.*)//; ## don't read past comments unless ($line =~ /\S/) {next;} ## skip blank lines - ($name, $value, $attemptLimit, $continueFlag) = split (/\s*,\s*/,$line); + # commas are valid in filenames, so we have to handle commas + # using backslash escaping, so \X will be replaced with X + my @line = (); + my $curr = ''; + for (my $i = 0; $i < length $line; $i++) { + my $c = substr($line,$i,1); + if ($c eq '\\') { + $curr .= substr($line,++$i,1); + } elsif ($c eq ',') { + push @line, $curr; + $curr = ''; + } else { + $curr .= $c; + } + } + ($name, $value, $attemptLimit, $continueFlag) = @line; + ##################### # clean up problem values ########################### @@ -1814,6 +1830,11 @@ my $source_file = $problemRecord->source_file(); my $value = $problemRecord->value(); my $max_attempts = $problemRecord->max_attempts(); + + # backslash-escape commas in fields + $source_file =~ s/([,\\])/\\$1/g; + $value =~ s/([,\\])/\\$1/g; + $max_attempts =~ s/([,\\])/\\$1/g; $problemList .= "$source_file, $value, $max_attempts \n"; } |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:31:23
|
Log Message: ----------- backport (sh002i): ignore .svn directories in problem libraries (%ignoredir) Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: SetMaker.pm Revision Data ------------- Index: SetMaker.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v retrieving revision 1.77.2.1 retrieving revision 1.77.2.2 diff -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -u -r1.77.2.1 -r1.77.2.2 --- lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -70,7 +70,7 @@ my %problib; ## filled in in global.conf my %ignoredir = ( '.' => 1, '..' => 1, 'Library' => 1, 'CVS' => 1, 'tmpEdit' => 1, - 'headers' => 1, 'macros' => 1, 'email' => 1, + 'headers' => 1, 'macros' => 1, 'email' => 1, '.svn' => 1, ); sub prepare_activity_entry { |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:30:40
|
Log Message: ----------- backport (jj): Add more indexing, small disk space expense and hopefully more speed. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/bin: NPL-update Revision Data ------------- Index: NPL-update =================================================================== RCS file: /webwork/cvs/system/webwork2/bin/NPL-update,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -Lbin/NPL-update -Lbin/NPL-update -u -r1.1.2.3 -r1.1.2.4 --- bin/NPL-update +++ bin/NPL-update @@ -102,6 +102,8 @@ number int(3), name varchar(127) NOT NULL, page int(4), + KEY (textbook_id, name), + KEY (number), PRIMARY KEY (chapter_id) '], ['NPL-section', ' @@ -110,6 +112,8 @@ number int(3), name varchar(127) NOT NULL, page int(4), + KEY (chapter_id, name), + KEY (number), PRIMARY KEY section (section_id) '], ['NPL-problem', ' |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:30:15
|
Log Message: ----------- backport (jj): Textbook chapters and sections will now include their numbers in the library browser, and be sorted accordingly. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/Utils: ListingDB.pm Revision Data ------------- Index: ListingDB.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Utils/ListingDB.pm,v retrieving revision 1.15.2.3 retrieving revision 1.15.2.4 diff -Llib/WeBWorK/Utils/ListingDB.pm -Llib/WeBWorK/Utils/ListingDB.pm -u -r1.15.2.3 -r1.15.2.4 --- lib/WeBWorK/Utils/ListingDB.pm +++ lib/WeBWorK/Utils/ListingDB.pm @@ -23,9 +23,9 @@ use constant LIBRARY_STRUCTURE => { textbook => { select => 'tbk.textbook_id,tbk.title,tbk.author,tbk.edition', name => 'library_textbook', where => 'tbk.textbook_id'}, - textchapter => { select => 'tc.name', name=>'library_textchapter', + textchapter => { select => 'tc.number,tc.name', name=>'library_textchapter', where => 'tc.name'}, - textsection => { select => 'ts.name', name=>'library_textsection', + textsection => { select => 'ts.number,ts.name', name=>'library_textsection', where => 'ts.name'}, problem => { select => 'prob.name' }, }; @@ -137,6 +137,7 @@ } my $textchap = $r->param('library_textchapter') || ''; + $textchap =~ s/^\s*\d+\.\s*//; if($textchap and $thing eq 'textsection') { $textextrawhere .= " AND tc.name=\"$textchap\" "; } else { @@ -169,9 +170,10 @@ @texts = indirectSortByName( \@sortarray, @texts ); return(\@texts); } else { - @texts = grep { $_->[0] =~ /\S/ } @texts; - my @sortarray = map { $_->[0] } @texts; - @texts = indirectSortByName( \@sortarray, @texts ); + @texts = grep { $_->[1] =~ /\S/ } @texts; + my @sortarray = map { $_->[0] .". " . $_->[1] } @texts; + @texts = map { [ $_ ] } @sortarray; + @texts = indirectSortByName(\@sortarray, @texts); return(\@texts); } } @@ -268,8 +270,7 @@ $kw1 = ", `NPL-keyword` kw, `NPL-pgfile-keyword` pgkey"; $kw2 = " AND kw.keyword_id=pgkey.keyword_id AND pgkey.pgfile_id=pgf.pgfile_id ". - makeKeywordWhere($keywords) - ; + makeKeywordWhere($keywords) ; } my $dbh = getDB($ce); @@ -291,6 +292,7 @@ my $haveTextInfo=0; for my $j (qw( textbook textchapter textsection )) { my $foo = $r->param(LIBRARY_STRUCTURE->{$j}{name}) || ''; + $foo =~ s/^\s*\d+\.\s*//; if($foo) { $haveTextInfo=1; $foo =~ s/'/\\'/g; |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:29:51
|
Log Message: ----------- backport (jj): Improved handling of textook chapters and sections (should be entered based on their number, not the DBchapter and DBsection name). Also improved handling for problems which are tagged to a chapter, but not to a particular seciton in the chapter. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/bin: NPL-update Revision Data ------------- Index: NPL-update =================================================================== RCS file: /webwork/cvs/system/webwork2/bin/NPL-update,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -Lbin/NPL-update -Lbin/NPL-update -u -r1.1.2.2 -r1.1.2.3 --- bin/NPL-update +++ bin/NPL-update @@ -148,18 +148,15 @@ my $passwd = $ce->{database_password}; my $user = $ce->{database_username}; my $libraryRoot = $ce->{problemLibrary}->{root}; -my $verbose =0; -my $cnt = 0; +my $verbose = 0; my $cnt2 = 0; $| = 1; # autoflush output sub dbug { my $msg = shift; - $cnt++; - print $msg if($verbose>1); - # if($cnt==5000) { print "\n"; $cnt=0;} - print "." if($verbose==1 and ($cnt % 100 == 0)); + my $insignificance = shift || 2; + print $msg if($verbose>=$insignificance); } ## Resetting the database tables. @@ -234,7 +231,7 @@ } } else { # We have a chapter entry if(defined($bookid)) { - my $query = "SELECT chapter_id FROM `NPL-chapter` WHERE textbook_id = \"$bookid\" AND name = \"$chapsec\""; + my $query = "SELECT chapter_id FROM `NPL-chapter` WHERE textbook_id = \"$bookid\" AND number = \"$chapsec\""; my $chapid = $dbh->selectrow_array($query); if (!defined($chapid)) { $dbh->do("INSERT INTO `NPL-chapter` @@ -246,7 +243,24 @@ \"\" )" ); - dbug "INSERT INTO chapter VALUES(\"\", \"$bookid\", \"".$chapsec."\", \"$title\", \"\" )\n"; + $chapid = $dbh->selectrow_array($query); + + # Add dummy section entry for problems tagged to the chapter + # without a section + $query = "SELECT section_id FROM `NPL-section` WHERE chapter_id = \"$chapid\" AND number = -1"; + my $sectid = $dbh->selectrow_array($query); + if (!defined($sectid)) { + $dbh->do("INSERT INTO `NPL-section` + VALUES( + \"\", + \"$chapid\", + \"-1\", + \"\", + \"\" + )" + ); + dbug "INSERT INTO section VALUES(\"\", \"$chapid\", \"-1\", \"\", \"\" )\n"; + } } } else { print "Cannot enter chapter $chapsec because textbook information is incomplete\n"; @@ -421,8 +435,7 @@ $textinfo{$textno}->{section} = $2; } else { $textinfo{$textno}->{chapter} = $textsection; - $textinfo{$textno}->{section} = ''; - # used to be: $chapnum = undef; #no valid number assigned + $textinfo{$textno}->{section} = -1; } } @@ -653,13 +666,13 @@ )" ); dbug "INSERT INTO textbook VALUES( \"\", \"$text\", \"$edition\", \"$textauthor\", \"\", \"\", \"\" )\n"; -# print "\nLate add into NPL-textbook \"$text\", \"$edition\", \"$textauthor\"\n"; + dbug "\nLate add into NPL-textbook \"$text\", \"$edition\", \"$textauthor\"\n", 1; $textbook_id = $dbh->selectrow_array($query); } # chapter weak table of textbook # - $query = "SELECT chapter_id FROM `NPL-chapter` WHERE textbook_id = \"$textbook_id\" AND name = \"$chapter\""; + $query = "SELECT chapter_id FROM `NPL-chapter` WHERE textbook_id = \"$textbook_id\" AND number = \"$chapnum\""; my $chapter_id = $dbh->selectrow_array($query); if (!defined($chapter_id)) { $dbh->do("INSERT INTO `NPL-chapter` @@ -671,13 +684,15 @@ \"\" )" ); + dbug "\nLate add into NPL-textchapter \"$text\", \"$edition\", \"$textauthor\", $chapnum $chapter from $name\n", 1; dbug "INSERT INTO chapter VALUES(\"\", \"$textbook_id\", \"".$chapnum."\", \"$chapter\", \"\" )\n"; $chapter_id = $dbh->selectrow_array($query); } # section weak table of textbook # - $query = "SELECT section_id FROM `NPL-section` WHERE chapter_id = \"$chapter_id\" AND name = \"$section\""; + $section = '' if ($secnum < 0); + $query = "SELECT section_id FROM `NPL-section` WHERE chapter_id = \"$chapter_id\" AND number = \"$secnum\""; my $section_id = $dbh->selectrow_array($query); if (!defined($section_id)) { $dbh->do("INSERT INTO `NPL-section` @@ -690,6 +705,7 @@ )" ); dbug "INSERT INTO section VALUES(\"\", \"$textbook_id\", \"$secnum\", \"$section\", \"\" )\n"; + dbug "\nLate add into NPL-textsection \"$text\", \"$edition\", \"$textauthor\", $secnum $section from $name\n", 1; $section_id = $dbh->selectrow_array($query); } @@ -725,10 +741,10 @@ } } + #reset tag vars, they may not match the next text/file + $date =""; $textauthor=""; $textsection=""; + $chapter=""; $section=""; } - #reset tag vars, they may not match the next file - $date =""; $textauthor=""; $textsection=""; - $chapter=""; $section=""; } close(IN) or die "can not close: $!"; } |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:29:24
|
Log Message: ----------- backport (glarose): bug fix: somehow I seem to have mixed up the logic in the message that gets displayed on the sets page for tests that are still open/over time. Sam: if you can get this into 2.4, that'd be great. Thanks. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator: ProblemSets.pm Revision Data ------------- Index: ProblemSets.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm,v retrieving revision 1.88.2.1 retrieving revision 1.88.2.2 diff -Llib/WeBWorK/ContentGenerator/ProblemSets.pm -Llib/WeBWorK/ContentGenerator/ProblemSets.pm -u -r1.88.2.1 -r1.88.2.2 --- lib/WeBWorK/ContentGenerator/ProblemSets.pm +++ lib/WeBWorK/ContentGenerator/ProblemSets.pm @@ -393,7 +393,7 @@ $problemRecords[0]->num_incorrect() >= $set->attempts_per_version() ) { $status = "completed."; - } elsif ( $set->due_date() < time() + + } elsif ( time() > $set->due_date() + $self->r->ce->{gatewayGracePeriod} ) { $status = "over time: closed."; } else { |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:29:01
|
Log Message: ----------- backport (dpvc): Work around IE bug where pressing return submits a form but does not set the submit button's value properly in some circumstances. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: FileManager.pm Revision Data ------------- Index: FileManager.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm,v retrieving revision 1.26.2.2 retrieving revision 1.26.2.3 diff -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -u -r1.26.2.2 -r1.26.2.3 --- lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm +++ lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm @@ -133,7 +133,7 @@ $self->{courseRoot} = $courseRoot; $self->{courseName} = $courseName; - my $action = $r->param('action') || $r->param('formAction') || 'Init'; + my $action = $r->param('action') || $r->param('formAction') || $r->param("confirmed") || 'Init'; for ($action) { /^Refresh/i and do {$self->Refresh; last}; @@ -672,7 +672,7 @@ ); print CGI::end_table(); - print CGI::hidden({name=>"confirmed",value=>1}); + print CGI::hidden({name=>"confirmed",value=>"Delete"}); foreach my $file (@files) {print CGI::hidden({name=>"files",value=>$file})} $self->HiddenFlags; } @@ -892,7 +892,7 @@ ), ); print CGI::end_table(); - print CGI::hidden({name=>"confirmed", value=>1}); + print CGI::hidden({name=>"confirmed", value=>$button}); $self->HiddenFlags; print CGI::script("window.document.FileManager.name.focus()"); } |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:28:23
|
Log Message: ----------- backport (dpvc): Allow unpacking of .tar.gz and .tar files in addition to .tgz files. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: FileManager.pm Revision Data ------------- Index: FileManager.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm,v retrieving revision 1.26.2.1 retrieving revision 1.26.2.2 diff -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -u -r1.26.2.1 -r1.26.2.2 --- lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm +++ lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm @@ -245,7 +245,7 @@ var button = document.getElementById('MakeArchive'); button.value = 'Make Archive'; if (disabled) return; - if (!files.childNodes[files.selectedIndex].value.match(/\\.tgz\$/)) return; + if (!files.childNodes[files.selectedIndex].value.match(/\\.(tar|tar\\.gz|tgz)\$/)) return; for (var i = files.selectedIndex+1; i < files.length; i++) {if (files.childNodes[i].selected) return} button.value = 'Unpack Archive'; @@ -711,8 +711,8 @@ sub UnpackArchive { my $self = shift; my $archive = $self->getFile("unpack"); return unless $archive; - if ($archive !~ m/\.tgz$/) { - $self->addbadmessage("You can only unpack files ending in '.tgz'"); + if ($archive !~ m/\.(tar|tar\.gz|tgz)$/) { + $self->addbadmessage("You can only unpack files ending in '.tgz', '.tar' or '.tar.gz'"); } else { $self->unpack($archive); } @@ -721,9 +721,9 @@ sub unpack { my $self = shift; - my $archive = shift; + my $archive = shift; my $z = 'z'; $z = '' if $archive =~ m/\.tar$/; my $dir = $self->{courseRoot}.'/'.$self->{pwd}; - my $tar = "cd ".shell_quote($dir)." && $self->{ce}{externalPrograms}{tar} -vxzf ".shell_quote($archive); + my $tar = "cd ".shell_quote($dir)." && $self->{ce}{externalPrograms}{tar} -vx${z}f ".shell_quote($archive); my @files = readpipe $tar." 2>&1"; if ($? == 0) { my $n = scalar(@files); my $s = ($n == 1? "": "s"); @@ -855,7 +855,7 @@ if (-e $file) { $self->addgoodmessage("$type file '$name' uploaded successfully"); - if ($name =~ m/\.tgz$/ && $self->getFlag('unpack')) { + if ($name =~ m/\.(tar|tar\.gz|tgz)$/ && $self->getFlag('unpack')) { if ($self->unpack($name) && $self->getFlag('autodelete')) { if (unlink($file)) {$self->addgoodmessage("Archive '$name' deleted")} else {$self->addbadmessage("Can't delete archive '$name': $!")} |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:27:38
|
Log Message: ----------- backport (glarose): bug fix. when updating to hide set header display I assumed that the $db->getMergedSet($userToShow, $setID) would succeed, which isn't the case for a set that isn't assigned to any users (in particular, which isn't assigned to the instructor who is editing the set). this bug fix resolves that by instead using the global set to determine if headers should be displayed when the call to get the merged set fails. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: ProblemSetDetail.pm Revision Data ------------- Index: ProblemSetDetail.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm,v retrieving revision 1.64.2.3 retrieving revision 1.64.2.4 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm -u -r1.64.2.3 -r1.64.2.4 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm @@ -1713,6 +1713,14 @@ my %error; my $this_set = $db->getMergedSet($userToShow, $setID); + my $guaranteed_set = $this_set; + if ( ! $guaranteed_set ) { + # in the header loop we need to have a set that + # we know exists, so if the getMergedSet failed + # (that is, the set isn't assigned to the + # the current user), we get the global set instead + $guaranteed_set = $db->getGlobalSet( $setID ); + } foreach my $header (@headers) { @@ -1746,7 +1754,7 @@ # edit/view it in this context, so we don't show this # field for gateway tests if ( $header eq 'set_header' && - $this_set->assignment_type =~ /gateway/ ) { + $guaranteed_set->assignment_type =~ /gateway/ ) { print CGI::Tr({}, CGI::td({}, [ "Set Header", "Set headers are not used in " . |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:22:29
|
Log Message: ----------- forward-port (sh002i): Resolve bug #1293 by actually throwing a RecordExists exception from NewSQL::Std. Modified Files: -------------- webwork2/lib/WeBWorK: DB.pm webwork2/lib/WeBWorK/DB: Schema.pm webwork2/lib/WeBWorK/DB/Schema/NewSQL: Std.pm Revision Data ------------- Index: DB.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB.pm,v retrieving revision 1.106 retrieving revision 1.107 diff -Llib/WeBWorK/DB.pm -Llib/WeBWorK/DB.pm -u -r1.106 -r1.107 --- lib/WeBWorK/DB.pm +++ lib/WeBWorK/DB.pm @@ -447,7 +447,7 @@ eval { return $self->{user}->add($User); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUser: user exists (perhaps you meant to use putUser?)"; } elsif ($@) { die $@; @@ -552,7 +552,7 @@ eval { return $self->{password}->add($Password); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addPassword: password exists (perhaps you meant to use putPassword?)"; } elsif ($@) { die $@; @@ -645,7 +645,7 @@ eval { return $self->{permission}->add($PermissionLevel); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addPermissionLevel: permission level exists (perhaps you meant to use putPermissionLevel?)"; } elsif ($@) { die $@; @@ -731,7 +731,7 @@ eval { return $self->{key}->add($Key); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addKey: key exists (perhaps you meant to use putKey?)"; } elsif ($@) { die $@; @@ -864,7 +864,7 @@ eval { return $self->{locations}->add($Location); }; - if ( my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists ) { + if ( my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists ) { croak "addLocation: location exists (perhaps you meant to use putLocation?)"; } elsif ($@) { die $@; @@ -965,7 +965,7 @@ eval { return $self->{location_addresses}->add($LocationAddress); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addLocationAddress: location address exists (perhaps you meant to use putLocationAddress?)"; } elsif ($@) { die $@; @@ -1036,7 +1036,7 @@ return $self->{set}->add($GlobalSet); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalSet: global set exists (perhaps you meant to use putGlobalSet?)"; } elsif ($@) { die $@; @@ -1127,7 +1127,7 @@ eval { return $self->{set_user}->add($UserSet); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserSet: user set exists (perhaps you meant to use putUserSet?)"; } elsif ($@) { die $@; @@ -1239,7 +1239,7 @@ eval { return $self->{set_version}->add($SetVersion); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addSetVersion: set version exists (perhaps you meant to use putSetVersion?)"; } elsif ($@) { die $@; @@ -1353,7 +1353,7 @@ eval { return $self->{set_locations}->add($GlobalSetLocation); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalSetLocation: global set_location exists (perhaps you meant to use putGlobalSetLocation?)"; } elsif ($@) { die $@; @@ -1452,7 +1452,7 @@ eval { return $self->{set_locations_user}->add($UserSetLocation); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserSetLocation: user set_location exists (perhaps you meant to use putUserSetLocation?)"; } elsif ($@) { die $@; @@ -1554,7 +1554,7 @@ eval { return $self->{problem}->add($GlobalProblem); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalProblem: global problem exists (perhaps you meant to use putGlobalProblem?)"; } elsif ($@) { die $@; @@ -1652,7 +1652,7 @@ eval { return $self->{problem_user}->add($UserProblem); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserProblem: user problem exists (perhaps you meant to use putUserProblem?)"; } elsif ($@) { die $@; @@ -1796,7 +1796,7 @@ eval { return $self->{problem_version}->add($ProblemVersion); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addProblemVersion: problem version exists (perhaps you meant to use putProblemVersion?)"; } elsif ($@) { die $@; Index: Schema.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Schema.pm,v retrieving revision 1.11 retrieving revision 1.12 diff -Llib/WeBWorK/DB/Schema.pm -Llib/WeBWorK/DB/Schema.pm -u -r1.11 -r1.12 --- lib/WeBWorK/DB/Schema.pm +++ lib/WeBWorK/DB/Schema.pm @@ -51,9 +51,9 @@ use warnings; use Exception::Class ( - 'WeBWorK::DB::Schema::Exception' => {}, - 'WeBWorK::DB::Schema::Exception::RecordExists' => { - isa => 'WeBWorK::DB::Schema::Exception', + 'WeBWorK::DB::Schema::Ex' => {}, + 'WeBWorK::DB::Schema::Ex::RecordExists' => { + isa => 'WeBWorK::DB::Schema::Ex', }, ); Index: Std.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Schema/NewSQL/Std.pm,v retrieving revision 1.15 retrieving revision 1.16 diff -Llib/WeBWorK/DB/Schema/NewSQL/Std.pm -Llib/WeBWorK/DB/Schema/NewSQL/Std.pm -u -r1.15 -r1.16 --- lib/WeBWorK/DB/Schema/NewSQL/Std.pm +++ lib/WeBWorK/DB/Schema/NewSQL/Std.pm @@ -61,6 +61,9 @@ $self->sql_init; + # provide a custom error handler + $self->dbh->{HandleError} = \&handle_error; + return $self; } @@ -732,4 +735,24 @@ } } +# maps error numbers to exception classes for MySQL +our %MYSQL_ERROR_CODES = ( + 1062 => 'WeBWorK::DB::Schema::Ex::RecordExists', +); + +# turns MySQL error codes into excpetions -- WeBWorK::DB::Schema::Ex objects +# for known error types, and normal die STRING exceptions for unknown errors. +# This is one method you'd want to override if you were writing a subclass for +# another RDBMS. +sub handle_error { + my ($errmsg, $handle, $returned) = @_; + + if (exists $MYSQL_ERROR_CODES{$handle->err}) { + $MYSQL_ERROR_CODES{$handle->err}->throw; + } else { + die $errmsg; + } +} + 1; + |
From: Sam H. v. a. <we...@ma...> - 2007-08-25 18:21:04
|
Log Message: ----------- Resolve bug #1293 by actually throwing a RecordExists exception from NewSQL::Std. Tags: ---- rel-2-4-dev Modified Files: -------------- webwork2/lib/WeBWorK: DB.pm webwork2/lib/WeBWorK/DB: Schema.pm webwork2/lib/WeBWorK/DB/Schema/NewSQL: Std.pm Revision Data ------------- Index: DB.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB.pm,v retrieving revision 1.104.2.1 retrieving revision 1.104.2.2 diff -Llib/WeBWorK/DB.pm -Llib/WeBWorK/DB.pm -u -r1.104.2.1 -r1.104.2.2 --- lib/WeBWorK/DB.pm +++ lib/WeBWorK/DB.pm @@ -378,7 +378,7 @@ eval { return $self->{user}->add($User); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUser: user exists (perhaps you meant to use putUser?)"; } elsif ($@) { die $@; @@ -483,7 +483,7 @@ eval { return $self->{password}->add($Password); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addPassword: password exists (perhaps you meant to use putPassword?)"; } elsif ($@) { die $@; @@ -576,7 +576,7 @@ eval { return $self->{permission}->add($PermissionLevel); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addPermissionLevel: permission level exists (perhaps you meant to use putPermissionLevel?)"; } elsif ($@) { die $@; @@ -662,7 +662,7 @@ eval { return $self->{key}->add($Key); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addKey: key exists (perhaps you meant to use putKey?)"; } elsif ($@) { die $@; @@ -746,7 +746,7 @@ eval { return $self->{locations}->add($Location); }; - if ( my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists ) { + if ( my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists ) { croak "addLocation: location exists (perhaps you meant to use putLocation?)"; } elsif ($@) { die $@; @@ -847,7 +847,7 @@ eval { return $self->{location_addresses}->add($LocationAddress); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addLocationAddress: location address exists (perhaps you meant to use putLocationAddress?)"; } elsif ($@) { die $@; @@ -918,7 +918,7 @@ return $self->{set}->add($GlobalSet); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalSet: global set exists (perhaps you meant to use putGlobalSet?)"; } elsif ($@) { die $@; @@ -1009,7 +1009,7 @@ eval { return $self->{set_user}->add($UserSet); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserSet: user set exists (perhaps you meant to use putUserSet?)"; } elsif ($@) { die $@; @@ -1121,7 +1121,7 @@ eval { return $self->{set_version}->add($SetVersion); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addSetVersion: set version exists (perhaps you meant to use putSetVersion?)"; } elsif ($@) { die $@; @@ -1235,7 +1235,7 @@ eval { return $self->{set_locations}->add($GlobalSetLocation); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalSetLocation: global set_location exists (perhaps you meant to use putGlobalSetLocation?)"; } elsif ($@) { die $@; @@ -1334,7 +1334,7 @@ eval { return $self->{set_locations_user}->add($UserSetLocation); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserSetLocation: user set_location exists (perhaps you meant to use putUserSetLocation?)"; } elsif ($@) { die $@; @@ -1436,7 +1436,7 @@ eval { return $self->{problem}->add($GlobalProblem); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addGlobalProblem: global problem exists (perhaps you meant to use putGlobalProblem?)"; } elsif ($@) { die $@; @@ -1534,7 +1534,7 @@ eval { return $self->{problem_user}->add($UserProblem); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addUserProblem: user problem exists (perhaps you meant to use putUserProblem?)"; } elsif ($@) { die $@; @@ -1678,7 +1678,7 @@ eval { return $self->{problem_version}->add($ProblemVersion); }; - if (my $ex = caught WeBWorK::DB::Schema::Exception::RecordExists) { + if (my $ex = caught WeBWorK::DB::Schema::Ex::RecordExists) { croak "addProblemVersion: problem version exists (perhaps you meant to use putProblemVersion?)"; } elsif ($@) { die $@; Index: Schema.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Schema.pm,v retrieving revision 1.10.4.1 retrieving revision 1.10.4.2 diff -Llib/WeBWorK/DB/Schema.pm -Llib/WeBWorK/DB/Schema.pm -u -r1.10.4.1 -r1.10.4.2 --- lib/WeBWorK/DB/Schema.pm +++ lib/WeBWorK/DB/Schema.pm @@ -51,9 +51,9 @@ use warnings; use Exception::Class ( - 'WeBWorK::DB::Schema::Exception' => {}, - 'WeBWorK::DB::Schema::Exception::RecordExists' => { - isa => 'WeBWorK::DB::Schema::Exception', + 'WeBWorK::DB::Schema::Ex' => {}, + 'WeBWorK::DB::Schema::Ex::RecordExists' => { + isa => 'WeBWorK::DB::Schema::Ex', }, ); Index: Std.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Schema/NewSQL/Std.pm,v retrieving revision 1.10.2.1 retrieving revision 1.10.2.2 diff -Llib/WeBWorK/DB/Schema/NewSQL/Std.pm -Llib/WeBWorK/DB/Schema/NewSQL/Std.pm -u -r1.10.2.1 -r1.10.2.2 --- lib/WeBWorK/DB/Schema/NewSQL/Std.pm +++ lib/WeBWorK/DB/Schema/NewSQL/Std.pm @@ -59,6 +59,9 @@ $self->sql_init; + # provide a custom error handler + $self->dbh->{HandleError} = \&handle_error; + return $self; } @@ -644,4 +647,24 @@ } } +# maps error numbers to exception classes for MySQL +our %MYSQL_ERROR_CODES = ( + 1062 => 'WeBWorK::DB::Schema::Ex::RecordExists', +); + +# turns MySQL error codes into excpetions -- WeBWorK::DB::Schema::Ex objects +# for known error types, and normal die STRING exceptions for unknown errors. +# This is one method you'd want to override if you were writing a subclass for +# another RDBMS. +sub handle_error { + my ($errmsg, $handle, $returned) = @_; + + if (exists $MYSQL_ERROR_CODES{$handle->err}) { + $MYSQL_ERROR_CODES{$handle->err}->throw; + } else { + die $errmsg; + } +} + 1; + |
From: Sam H. v. a. <we...@ma...> - 2007-08-24 18:45:46
|
Log Message: ----------- Extended the set definition file format to support commas in the source_file field (as well was the value and max_attempts fields). Commas are backslash escaped: \, To get a literal backslash: \\ Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: ProblemSetList.pm Revision Data ------------- Index: ProblemSetList.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm,v retrieving revision 1.104 retrieving revision 1.105 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -u -r1.104 -r1.105 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm @@ -1718,7 +1718,23 @@ $line =~ s/(#.*)//; ## don't read past comments unless ($line =~ /\S/) {next;} ## skip blank lines - ($name, $value, $attemptLimit, $continueFlag) = split (/\s*,\s*/,$line); + # commas are valid in filenames, so we have to handle commas + # using backslash escaping, so \X will be replaced with X + my @line = (); + my $curr = ''; + for (my $i = 0; $i < length $line; $i++) { + my $c = substr($line,$i,1); + if ($c eq '\\') { + $curr .= substr($line,++$i,1); + } elsif ($c eq ',') { + push @line, $curr; + $curr = ''; + } else { + $curr .= $c; + } + } + ($name, $value, $attemptLimit, $continueFlag) = @line; + ##################### # clean up problem values ########################### @@ -1814,6 +1830,11 @@ my $source_file = $problemRecord->source_file(); my $value = $problemRecord->value(); my $max_attempts = $problemRecord->max_attempts(); + + # backslash-escape commas in fields + $source_file =~ s/([,\\])/\\$1/g; + $value =~ s/([,\\])/\\$1/g; + $max_attempts =~ s/([,\\])/\\$1/g; $problemList .= "$source_file, $value, $max_attempts \n"; } |
From: Sam H. v. a. <we...@ma...> - 2007-08-24 18:15:39
|
Log Message: ----------- ignore .svn directories in problem libraries (%ignoredir) Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: SetMaker.pm Revision Data ------------- Index: SetMaker.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v retrieving revision 1.79 retrieving revision 1.80 diff -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -u -r1.79 -r1.80 --- lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -70,7 +70,7 @@ my %problib; ## filled in in global.conf my %ignoredir = ( '.' => 1, '..' => 1, 'Library' => 1, 'CVS' => 1, 'tmpEdit' => 1, - 'headers' => 1, 'macros' => 1, 'email' => 1, + 'headers' => 1, 'macros' => 1, 'email' => 1, '.svn' => 1, ); sub prepare_activity_entry { |