-
-
Notifications
You must be signed in to change notification settings - Fork 80
PGML::Format Refactoring #1358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
PGML::Format Refactoring #1358
Conversation
8a1ff45 to
5743412
Compare
macros/core/PGML.pl
Outdated
| for my $i (0 .. $n - 1) { | ||
| my $item = $stack->[$i]; | ||
| my $next_par = $i + 1 < $n && $stack->[ $i + 1 ]{type} eq 'par' ? $stack->[ $i + 1 ] : undef; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this to
| for my $i (0 .. $n - 1) { | |
| my $item = $stack->[$i]; | |
| my $next_par = $i + 1 < $n && $stack->[ $i + 1 ]{type} eq 'par' ? $stack->[ $i + 1 ] : undef; | |
| for my $i (0 .. $#$stack) { | |
| my $item = $stack->[$i]; | |
| my $next_par = $i < $#$stack && $stack->[ $i + 1 ]{type} eq 'par' ? $stack->[ $i + 1 ] : undef; |
and delete my $n = scalar(@$stack); above (line 1271). Perl is optimized for this and stores this number as a property of the array. So there is no reason to save the array length to yet another location. Also, perl offers the $# syntax for getting the index of the last entry in an array, so use that rather than adding or subtracting one from the array length.
5743412 to
fc008f1
Compare
drgrice1
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good.
I think that the essential thing is that the divs that were added between list items be fixed, since that is invalid HTML. Adding the style to other block items (such as the lists themself) instead of injecting an empty div after it is not particularly important since that is at least valid HTML. I am not entirely certain what benefit that provides either.
|
I am unsure on the benefit as well, but I do feel the empty divs for spacing is not ideal. I was also wondering if there were any accessibility issues with not using Paragraph one.
<div style="margin-top:1em"></div>
Paragraph two.
<div style="margin-top:1em"></div>
Paragraph three.And this just feels better to me. But I couldn't figure out a way to do this, and assume that if the PGML parser was setup for this, <div style="margin-bottom:1em">
Paragraph one.
</div>
<div style="margin-bottom:1em">
Paragraph two.
</div>
<div style="margin:0">
Paragraph three.
</div> |
|
There is nothing wrong with using an empty Using |
|
I agree with @drgrice1 that removing the As for the implementation itself, I had considered something like this in my suggestion, but because this is in the base In fact, I had considered something more general yet. Were I writing this code today (rather than something like 20 years ago), I would replace the whole my $method = ucfirst($item->{type});
if (Value::can($self, $method)) {
$string = $self->$method($item, $block, $i);
} else {
PGML::Warning "Warning: unknown block type '$item->{type}' in " . ref($self) . "::format\n";
}In fact, I might replace the main loop by my $string, $di;
for (my $i = 0; $i < $#$stack; $i += 1 + ($di || 0)) {
my $item = $self->{item} = $stack->[$i];
$self->{nl} = (!defined($strings[-1]) || $strings[-1] =~ m/\n$/ ? "" : "\n");
my $method = ucfirst($item->{type});
if (Value::can($self, $method)) {
($string, $di) = $self->$method($item, $block, $i);
push(@strings, $string) unless !defined $string || $string eq '';
} else {
PGML::Warning "Warning: unknown block type '$item->{type}' in " . ref($self) . "::format\n";
}
}Then the various methods could check the stack in any way they wanted to (not just know about a following This makes all the item implementations get the same data and work the same way. It allows the creation of new item types without having to modify the main loop. And it allows the item implementations to deal with the block's stack in whatever way they need to. Finally, it avoids all the pattern matching done and the awkward Anyway, this would mean that you don't have to keep adding extra parameters to specific item implementations in the future, and all items are implemented in the same way. |
|
@dpvc Thanks. I am looking at implementing what you stated, but unsure how to modify the |
|
Sorry, I missed the string being sent to the my $state = {
block => $block,
strings => [],
i => 0,
};
while ($state->{i} < $#$stack) {
my $item = $self->{item} = $stack->[$state->{i}++];
$self->{nl} = (!defined($state->{strings}[-1]) || $state->{strings}[-1] =~ m/\n$/ ? "" : "\n");
my $method = ucfirst($item->{type});
if (Value::can($self, $method)) {
my $string = $self->$method($item, $state);
push(@{$state->{strings}}, $string) unless !defined $string || $string eq '';
} else {
PGML::Warning "Warning: unknown block type '$item->{type}' in " . ref($self) . "::format\n";
}
}Then Of course, this requires changes to the implementation functions that previously used |
|
Implemented the suggested changes to the main |
92ac3ed to
094666c
Compare
|
Seems my change missed adding a new line character that makes one of the unit tests fails. Trying to track that down unless someone else sees where a newline wasn't added correctly. |
macros/core/PGML.pl
Outdated
| my $self = shift; | ||
| my $item = shift; | ||
| return $self->nl . '<div style="margin-top:1em"></div>' . "\n"; | ||
| return '<div style="margin-top:1em"></div>' . "\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unit test is failing because of the removal of $self->nl . here. This removal seems to be an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I should add that for the PGML::Format::html package, almost all of these new lines should be removed. I think that at some point there was an attempt to make the resulting output more human readable by adding these newlines. However, that also results in larger output that is sent. That is not desirable, and instead minimized html code should be the goal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yea it was an error, in trying to revert the Par function I missed that.
I could go remove some of those new lines if you would like, though maybe that should be a new PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, lets leave that for another pull request.
094666c to
a013860
Compare
drgrice1
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we are fixing HTML validation issues here, there is one more that I have observed. On line 1638 (in this pull request at least), there is a span tag that contains an hr tag. It is invalid for a span to contain an hr. That can be easily fixed by changing that span to a div. That will not affect the resulting display, and is then valid HTML.
You could add that to this pull request if you like.
Apply the spacing between paragraphs added by the Par block in in HTML to the previous block instead of inserting an empty div with a margin. This adds the margin from the Par block to the previous Indent div, list, or list item block. Based on the code from @dpvc in openwebwork#1355.
As suggested by @dvpc, refactor the PGML::format::string loop to call the appropriate method if it exists. Also all methods now have access to the block and current state of the loop to use as needed.
e299780 to
154e463
Compare
This was never used anywhere else (that I could find), so no need to store the current item in the PGML::format::string loop.
dpvc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK with this as is, but regarding passing $block, I think it makes more sense to put that into the state and modify the few functions that use that. I almost put $item into that as well, but didn't want you to have to edit every function. But there are only a couple that use $block.
macros/core/PGML.pl
Outdated
| /tag/ && do { $string = $self->Tag($item); last }; | ||
| my ($self, $block) = @_; | ||
| my $stack = $block->{stack}; | ||
| my $state = { strings => [], i => 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On looking at this, with all the $state->{strings}[-1] references I'm wondering if it wouldn't be better to do
my @strings;
my $state = { strings => \@strings, i => 0 };so that 1275 can go back to its original form, as can 1283 and 1284, and 1278 can use @strings.
macros/core/PGML.pl
Outdated
| . "</div>\n"; | ||
| my $em = 2.25 * $item->{indent}; | ||
| my $bottom = '0'; | ||
| if (defined $block->{stack}[ $state->{i} ] && $block->{stack}[ $state->{i} ]{type} eq 'par') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be useful to do
my $next = $block->{stack}[ $state->{i} ];
if (defined $next && $next->type eq 'par') {to reduce the number of dereferences that need to be performed. Similarly for lines 1544 and 1558.
macros/core/PGML.pl
Outdated
| $bottom = '1em'; | ||
| $state->{i}++; | ||
| } | ||
| return $self->nl . "<div style=\"margin: 0 0 $bottom ${em}em;\">\n" . $self->string($item) . $self->nl . "</div>\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really are trying to save individual characters being part of the HTML output, then remove the semi-colon after '${em}em' and the \n at the end, here.
macros/core/PGML.pl
Outdated
| my $list = $bullet{ $item->{bullet} }; | ||
| my $margin = '0'; | ||
| if (defined $block->{stack}[ $state->{i} ] && $block->{stack}[ $state->{i} ]{type} eq 'par') { | ||
| $margin = '0 0 1em 0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, if you want to reduce characters, leave off the final 0, which is implied by the second 0.
|
@dpvc thanks for the suggestions, I'll go make some of the changes. I party didn't include |
All of the format methods now receive a single state hash instead of the item, block, and state as separate inputs. Reduce the number of times some variables are dereferenced from the state hash. Remove some white space to minimize HTML output. Leaving newline characters `\n` alone for now.
|
I appreciate your making those changes. That alls looks good. One last thing I just thought of is that the new |
|
I think that changing So I am just up voting @dpvc's last suggestion! |
This way only "item" methods are capitalized to distinguish them from other methods which are not a block item type.
|
The method is now called |
|
Since I was updating a bunch of things, I went one step further and followed the suggestion of removing the new line characters from the html output (in addition moving a few space characters as well). I also switched all the html format methods to use Another thing I noticed, but left alone, is the br tags are |
af354d4 to
f172401
Compare
Since newlines and spaces are extra characters to send, minimize the HTML output by removing any new line or unneeded space characters. In addition switch to using `main::tag` to create the html tags.
f172401 to
d0531d5
Compare
Lots of changes since last approval.
Refactor the PGML::Format package, which includes changing how it is used, and cleaning up HTML output (including fixing some invalid HTML issues).
Refactors how the methods to format the different PGML::Format item methods are called. Instead of using
an odd syntax for switch/cases,
/foo/ && do { ....; last }, just convert the itemtypeinto a method name and test if that method exists. Also all item methods are sent the same input, astatehash which includes the data they need to determine what output to produce.Fix some issues with invalid HTML, this means that the margin created by
parblocks are now appliedto the previous list, list item, or indent div, instead of creating an empty div. Also fixed an issue where an
hrtag was inside aspantag.Remove newlines and extra spaces from HTML output. These are extra characters that don't need to be sent to the client.
Use
main::tagto create the HTML tags used in the HTML output.Based on the code from @dpvc in #1355 and in the review of this PR.