Skip to content

Commit 144b7fb

Browse files
authored
Merge pull request #310 from openwebwork/PG-2.13
PG-2.13
2 parents f10279a + 73356d1 commit 144b7fb

33 files changed

+838
-204
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Online Homework Delivery System
33
Version 2.*
44

5-
Copyright 2000-2016, The WeBWorK Project
5+
Copyright 2000-2017, The WeBWorK Project
66
All rights reserved.
77

88
This program is free software; you can redistribute it and/or modify

README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66

77
http://webwork.maa.org/wiki/Category:Release_Notes
88

9-
Copyright 2000-2014, The WeBWorK Project
9+
Copyright 2000-2017, The WeBWorK Project
1010
http://webwork.maa.org
1111
All rights reserved.

VERSION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$PG_VERSION ='2.12';
2-
$PG_COPYRIGHT_YEARS = '1996-2016';
1+
$PG_VERSION ='PG-2.13';
2+
$PG_COPYRIGHT_YEARS = '1996-2017';
33

44
1;

lib/PGcore.pm

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ sub initialize {
112112
WARNING_messages => $self->{WARNING_messages},
113113
DEBUG_messages => $self->{DEBUG_messages},
114114
);
115-
$self->{maketext} = WeBWorK::Localize::getLoc($self->{envir}->{language});
115+
#$self->{maketext} = WeBWorK::Localize::getLoc($self->{envir}->{language});
116+
$self->{maketext} = $self->{envir}->{language_subroutine};
116117
#$self->debug_message("PG alias created", $self->{PG_alias} );
117118
$self->{PG_loadMacros} = new PGloadfiles($self->{envir});
118119
$self->{flags} = {
@@ -490,6 +491,8 @@ sub record_array_name { # currently the same as record ans name
490491
$label;
491492

492493
}
494+
495+
493496
sub extend_ans_group { # modifies the group type
494497
my $self = shift;
495498
my $label = shift;
@@ -506,6 +509,7 @@ sub extend_ans_group { # modifies the group type
506509
}
507510
$label;
508511
}
512+
509513
sub record_unlabeled_ans_name {
510514
my $self = shift;
511515
$self->{unlabeled_answer_blank_count}++;
@@ -720,8 +724,11 @@ sub insertGraph {
720724
721725
=cut
722726
sub maketext {
723-
my $self = shift;
724-
&{ $self->{maketext}}(@_);
727+
my $self = shift;
728+
# uncomment this to check to see if strings are run through
729+
# maketext.
730+
# return 'xXx'. &{ $self->{maketext}}(@_).'xXx';
731+
&{ $self->{maketext}}(@_);
725732
}
726733
sub includePGtext {
727734
my $self = shift;

lib/Parser/Differentiation.pm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ sub Parser::BOP::divide::D {
100100
$BOP->new($equation,'*',
101101
$self->{lop}->copy($equation),$self->{rop}->D($x))
102102
),
103-
$BOP->new($equation,'^',$self->{rop},$self->Item("Number")->new($equation,2))
103+
$BOP->new($equation,'^',$self->{rop}->copy($equation),
104+
$self->Item("Number")->new($equation,2))
104105
);
105106
return $self->reduce;
106107
}

lib/Parser/Legacy/NumberWithUnits.pm

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
package Parser::Legacy::ObjectWithUnits;
99

10+
# Refrences to problem specific copies of %Units::fundamental_units
11+
# and %Units::known_units. These should be passed to any Units function call.
12+
# They are set by the initializeUnits sub
13+
my $fundamental_units = '';
14+
my $known_units = '';
15+
1016
sub name {'object'};
1117
sub cmp_class {'an Object with Units'};
1218
sub makeValue {
@@ -15,10 +21,46 @@ sub makeValue {
1521
Value::makeValue($value,%options);
1622
}
1723

24+
sub initializeUnits {
25+
$fundamental_units = shift;
26+
$known_units = shift;
27+
}
28+
1829
sub new {
1930
my $self = shift; my $class = ref($self) || $self;
2031
my $context = (Value::isContext($_[0]) ? shift : $self->context);
21-
my $num = shift; my $units = shift;
32+
my $num = shift;
33+
# we need to check if units is the options hash
34+
my $units = shift;
35+
my $options;
36+
37+
if (ref($units) eq 'HASH') {
38+
$options = $units;
39+
$units = '';
40+
} else {
41+
$options = shift;
42+
}
43+
44+
# register a new unit/s if needed
45+
if (defined($options->{newUnit})) {
46+
my @newUnits;
47+
if (ref($options->{newUnit}) eq 'ARRAY') {
48+
@newUnits = @{$options->{newUnit}};
49+
} else {
50+
@newUnits = ($options->{newUnit});
51+
}
52+
53+
foreach my $newUnit (@newUnits) {
54+
if (ref($newUnit) eq 'HASH') {
55+
add_unit($newUnit->{name}, $newUnit->{conversion});
56+
} else {
57+
add_unit($newUnit);
58+
}
59+
}
60+
}
61+
62+
63+
2264
Value::Error("You must provide a ".$self->name) unless defined($num);
2365
($num,$units) = splitUnits($num) unless $units;
2466
Value::Error("You must provide units for your ".$self->name) unless $units;
@@ -37,17 +79,18 @@ sub new {
3779
#
3880
# Find the units for the formula and split that off
3981
#
40-
my $aUnit = '(?:'.getUnitNames().')(?:\s*(?:\^|\*\*)\s*[-+]?\d+)?';
41-
my $unitPattern = $aUnit.'(?:\s*[/* ]\s*'.$aUnit.')*';
42-
my $unitSpace = "($aUnit) +($aUnit)";
4382
sub splitUnits {
83+
my $aUnit = '(?:'.getUnitNames().')(?:\s*(?:\^|\*\*)\s*[-+]?\d+)?';
84+
my $unitPattern = $aUnit.'(?:\s*[/* ]\s*'.$aUnit.')*';
85+
my $unitSpace = "($aUnit) +($aUnit)";
4486
my $string = shift;
45-
my ($num,$units) = $string =~ m!^(.*?(?:[)}\]0-9a-z]|\d\.))\s*($unitPattern)\s*$!o;
87+
my ($num,$units) = $string =~ m!^(.*?(?:[)}\]0-9a-z]|\d\.))\s*($unitPattern)\s*$!;
4688
if ($units) {
4789
while ($units =~ s/$unitSpace/$1*$2/) {};
4890
$units =~ s/ //g;
4991
$units =~ s/\*\*/^/g;
5092
}
93+
5194
return ($num,$units);
5295
}
5396

@@ -57,18 +100,29 @@ sub splitUnits {
57100
#
58101
sub getUnitNames {
59102
local ($a,$b);
103+
my $units = \%Units::known_units;
104+
if ($known_units) {
105+
$units = $known_units;
106+
}
60107
join('|',sort {
61108
return length($b) <=> length($a) if length($a) != length($b);
62109
return $a cmp $b;
63-
} keys(%Units::known_units));
110+
} keys(%$units));
64111
}
65112

66113
#
67114
# Get the units hash and fix up the errors
68115
#
69116
sub getUnits {
70117
my $units = shift;
71-
my %Units = Units::evaluate_units($units);
118+
my $options = {};
119+
if ($fundamental_units) {
120+
$options->{fundamental_units} = $fundamental_units;
121+
}
122+
if ($known_units) {
123+
$options->{known_units} = $known_units;
124+
}
125+
my %Units = Units::evaluate_units($units,$options);
72126
if ($Units{ERROR}) {
73127
$Units{ERROR} =~ s/ at ([^ ]+) line \d+(\n|.)*//;
74128
$Units{ERROR} =~ s/^UNIT ERROR:? *//;
@@ -104,6 +158,7 @@ sub cmp_parse {
104158
#
105159
# Check that the units are defined and legal
106160
#
161+
107162
my ($num,$units) = splitUnits($ans->{student_ans});
108163
unless (defined($num) && defined($units) && $units ne '') {
109164
$self->cmp_Error($ans,"Your answer doesn't look like ".lc($self->cmp_class));
@@ -157,6 +212,31 @@ sub adjustCorrectValue {
157212

158213
sub cmp_reparse {Value::cmp_parse(@_)}
159214

215+
sub add_fundamental_unit {
216+
my $unit = shift;
217+
$fundamental_units->{$unit} = 0;
218+
}
219+
220+
sub add_unit {
221+
my $unit = shift;
222+
my $hash = shift;
223+
224+
unless (ref($hash) eq 'HASH') {
225+
$hash = {'factor' => 1,
226+
"$unit" => 1 };
227+
}
228+
229+
# make sure that if this unit is defined in terms of any other units
230+
# then those units are fundamental units.
231+
foreach my $subUnit (keys %$hash) {
232+
if (!defined($fundamental_units->{$subUnit})) {
233+
add_fundamental_unit($subUnit);
234+
}
235+
}
236+
237+
$known_units->{$unit} = $hash;
238+
}
239+
160240
######################################################################
161241

162242
#

lib/Rserve.pm

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package Rserve;
2+
3+
use strict;
4+
use warnings;
5+
6+
my $rserve_loaded = eval {
7+
require Statistics::R::IO::Rserve;
8+
1
9+
};
10+
11+
sub access {
12+
die 'Statistics::R::IO::Rserve could not be loaded. Have you installed the module?'
13+
unless $rserve_loaded;
14+
15+
Statistics::R::IO::Rserve->new(@_)
16+
};
17+
18+
19+
## Evaluates an R expression guarding it inside an R `try` function
20+
##
21+
## Returns the result as a REXP if no exceptions were raised, or
22+
## `die`s with the text of the exception message.
23+
sub try_eval {
24+
my ($rserve, $query) = @_;
25+
26+
my $result = $rserve->eval("try({ $query }, silent=TRUE)");
27+
die $result->to_pl->[0] if _inherits($result, 'try-error');
28+
# die $result->to_pl->[0] if $result->inherits('try-error');
29+
30+
$result
31+
}
32+
33+
34+
## Returns a REXP's Perl representation, dereferencing it if it's an
35+
## array reference
36+
##
37+
## `REXP::to_pl` returns a string scalar for Symbol, undef for Null,
38+
## and an array reference to contents for all vector types. This
39+
## function is a utility wrapper to make it easy to assign a Vector's
40+
## representation to an array variable, while still working sensibly
41+
## for non-arrays.
42+
sub unref_rexp {
43+
my $rexp = shift;
44+
45+
my $value = $rexp->to_pl;
46+
if (ref($value) eq ref([])) {
47+
@{$value}
48+
} else {
49+
$value
50+
}
51+
}
52+
53+
54+
## Reimplements method C<inherits> of class L<Statistics::R::REXP>
55+
## until I figure out why calling it directly doesn't work in the safe
56+
## compartment
57+
sub _inherits {
58+
my ($rexp, $class) = @_;
59+
60+
my $attributes = $rexp->attributes;
61+
return unless $attributes && $attributes->{'class'};
62+
63+
grep {/^$class$/} @{$attributes->{'class'}->to_pl}
64+
}
65+
66+
67+
1;

0 commit comments

Comments
 (0)