Skip to content

Commit

Permalink
Add a getSampleProblemCode method to SampleProblemParser.pm.
Browse files Browse the repository at this point in the history
This method is much more efficient than calling `parseSampleProblem` to
obtain the code as it does not parse documentation, does not require
that the sample problem metadata be parsed first, and it does not need
macro POD information.  Note that to obtain the code via the
`parseSampleProblem` method, 253 files need to be read and parsed (all
sample problems and all macros). The `getSampleProblemCode` method only
needs to read 1 file, and the parsing of that is more efficient as well.
It should be used if all you want is the code as it does not return the
documentation and other data returned by the `parseSampleProblem`
method.

Also remove the unused `$macro_locations` argument to the
`parseMetadata` method.

These changes are used to implement sample problem editing in the PG
problem editor for webwork2 in a corresponding pull request.
  • Loading branch information
drgrice1 committed Feb 20, 2025
1 parent 93043a3 commit 1e1695a
Showing 1 changed file with 40 additions and 3 deletions.
43 changes: 40 additions & 3 deletions lib/SampleProblemParser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use File::Basename qw(dirname basename);
use File::Find qw(find);
use Pandoc;

our @EXPORT_OK = qw(parseSampleProblem generateMetadata);
our @EXPORT_OK = qw(parseSampleProblem generateMetadata getSampleProblemCode);

=head1 NAME
Expand Down Expand Up @@ -150,7 +150,7 @@ sub generateMetadata ($problem_dir, %options) {
say "Reading file: $File::Find::name" if $options{verbose};

if ($File::Find::name =~ /\.pg$/) {
my $metadata = parseMetadata($File::Find::name, $problem_dir, $options{macro_locations});
my $metadata = parseMetadata($File::Find::name, $problem_dir);
unless (@{ $metadata->{types} }) {
warn "The type of sample problem is missing for $File::Find::name.";
return;
Expand All @@ -175,7 +175,7 @@ my @macros_to_skip = qw(
PGstandard.pl
);

sub parseMetadata ($path, $problem_dir, $macro_locations = {}) {
sub parseMetadata ($path, $problem_dir) {
open(my $FH, '<:encoding(UTF-8)', $path) or do {
warn qq{Could not open file "$path": $!};
return {};
Expand Down Expand Up @@ -228,4 +228,41 @@ sub parseMetadata ($path, $problem_dir, $macro_locations = {}) {
return $metadata;
}

=head2 C<getSampleProblemCode>
Parse a PG file with extra documentation comments and strip that all out
returning the clean problem code. This returns the same code that the
C<parseSampleProblem> returns, except at much less expense as it does not parse
the documentation, it does not require that the metadata be parsed first, and it
does not need macro POD information.
=cut

sub getSampleProblemCode ($file) {
my $filename = basename($file);
open(my $FH, '<:encoding(UTF-8)', $file) or do {
warn qq{Could not open file "$file": $!};
return '';
};
my @file_contents = <$FH>;
close $FH;

my (@code_rows, $inCode);

while (my $row = shift @file_contents) {
chomp($row);
$row =~ s/\t/ /g;
if ($row =~ /^#:(.*)?/) {
# This is documentation so skip it.
} elsif ($row =~ /^\s*(END)?DOCUMENT.*$/) {
$inCode = $1 ? 0 : 1;
push(@code_rows, $row);
} elsif ($inCode) {
push(@code_rows, $row);
}
}

return join("\n", @code_rows);
}

1;

0 comments on commit 1e1695a

Please # to comment.