Smart::Comments(3pm)
π Smart::Comments π
okay so bestie, pull up a chair, because we're talking about Smart::Comments (that's the Smart::Comments(3pm) page, perlmoms and perlthems π
). The official tagline? Comments that do more than just sit there. And likeβ¦ literally. They get UP. They do stuff. No cap. π
β¨ VERSION β¨
This page describes Smart::Comments version 1.000005. Yes, that's the number, I'm not rounding it, we don't do that here πΈ.
π SYNOPSIS π
use Smart::Comments;
my $var = suspect_value();
### $var
### got: $var
### Now computing value...
# and when looping:
for my $big_num (@big_nums) { ### Factoring... done
factor($big_num);
}
while ($error > $tolerance) { ### Refining---> done
refine_approximation()
}
for (my $i=0; $i<$MAX_INT; $i++) { ### Working===[%] done
do_something_expensive_with($i);
}
π¦ DESCRIPTION π¦
So the whole vibe of smart comments is: you wanna shove debugging and tracking code into your program, but you don't wanna do a whole production about it. Smart comments let you π
- report the value of a variable
- track the progress of a loop
- verify that particular assertions are true
And the bestie-est part? When you're done debugging, you do not have to remove them. Not even a little. You just comment out the use Smart::Comments line and they go back to being regular, boring, harmless comments πβ¨.
And honestly, leaving them in there is the smart move (the module name is not a coincidence, iykyk). Because if you needed them once, you're gonna need them again. That's just facts. Periodt. π
π INTERFACE π
Okay so literally every smart comment kicks off with three (or more) # characters. Translation: they're normal #-introduced comments, but their first two (or more) characters are also #'s. Sneaky. Iconic. Main character energy fr fr π
.
π Using the Module π
You load it like literally any other module:
use Smart::Comments;
Once it's loaded, it filters the remaining code up to the next:
no Smart::Comments;
directive, swapping out any smart comments for smart code that actually implements the behaviour the comment describes. Wild? Yes. Slay? Also yes.
If you're debugging an application, you can also just roll up on it from the command line:
perl -MSmart::Comments $application.pl
β οΈ heads up bestie: this only switches on smart comments in the application file itself β not in any modules the application loads. So don't come for me when your Foo::Bar is still being quiet.
You can also pick specific levels of smartness by passing one or more markers as arguments to the use:
use Smart::Comments '###', '####';
Those arguments tell the module to only filter comments that start with the same number of #'s. So that use up there would "activate" smart comments of the form:
### Smart...
#### Smarter...
but not ones like:
##### Smartest...
Why do we care? Because it lets you separate your progress bars (go read "Progress Bars" π) β which should always be live β from your debugging comments (go read "Debugging via Comments"), which absolutely should not be:
#### Debugging here...
for (@values) { ### Progress: 0... 100
do_stuff();
}
πΈ little note for simplicity's sake: every smart comment below is written with three#'s. But in all of those cases, any number of#'s greater than three would work just as well. Go off, use six, we don't judge.
π Debugging via Comments π
The simplest way to use smart comments is for debugging. The module supports the following forms, and all of them print to STDERR (yes, STDERR, not STDOUT, put that in your notes π):
### LABEL : EXPRESSIONβ here theLABELis any sequence of characters up to the first colon, and theEXPRESSIONis any valid Perl expression, including a simple variable. When active, the comment prints the label, followed by the value of the expression. Like so:
### Expected: 2 * $prediction
### Got: $result
which prints:
### Expected: 42
### Got: 13
### EXPRESSIONβ theEXPRESSIONis any valid Perl expression, including a simple variable. When active, the comment prints the expression, followed by its value. For example:
### 2 * $prediction
### $result
prints:
### 2 * $prediction: 42
### $result: 13
### TEXT...β theTEXTis any sequence of characters that end in three dots. When active, the comment just prints the text, including the dots. For example:
### Acquiring data...
$data = get_data();
### Verifying data...
verify_data($data);
### Assimilating data...
assimilate_data($data);
### Tired now, having a little lie down...
sleep 900;
would print:
### Acquiring data...
### Verifying data...
### Assimilating data...
### Tired now, having a little lie down...
as each phase commenced. This is particularly useful for tracking down precisely where a bug is occurring β like a little breadcrumb trail of vibes π. It's also useful in non-debugging situations, especially batch processing, as a simple progress feedback mechanism. Very demure, very mindful.
Now inside a textual smart comment you can use the special sequence <now> (or <time>, or <when>) and it gets replaced with a timestamp. For example:
### [<now>] Acquiring data...
would produce something like:
### [Fri Nov 18 15:11:15 EST 2005] Acquiring data...
There are also "spacestamps": <here> (or <loc>, or <place>, or <where>):
### Acquiring data at <loc>...
to produce something like:
### Acquiring data at "demo.pl", line 7...
You can also request just the filename (<file>) or just the line number (<line>) for finer control over the formatting:
### Acquiring data at <file>[<line>]...
and produce something like:
### Acquiring data at demo.pl[7]...
And you can, of course, use any combination of stamps in the one comment. Mix and match, it's your world π.
π₯ Checks and Assertions via Comments π₯
### require: BOOLEAN_EXPR### assert: BOOLEAN_EXPR### ensure: BOOLEAN_EXPR### insist: BOOLEAN_EXPR
These four are synonyms for the same behaviour, so pick whichever one hits right. The comment evaluates the expression in a boolean context. If the result is true, nothing more is done β chill, we move on. But if the result is false, the comment throws an exception listing the expression, the fact that it failed, and the values of any variables used in the expression. Snitch behaviour, honestly, but for your own good π.
For example, given the following assertion:
### require: $min < $result && $result < $max
if the expression evaluated false, the comment would die with the following message:
### $min < $result && $result < $max was not true at demo.pl line 86.
### $min was: 7
### $result was: 1000004
### $max was: 99
### check: BOOLEAN_EXPR### confirm: BOOLEAN_EXPR### verify: BOOLEAN_EXPR
These three are synonyms for the same behaviour too. The comment evaluates the expression in a boolean context. True? Nothing more is done, carry on queen. False? The comment prints a warning message listing the expression, the fact that it failed, and the values of any variables used in the expression.
The effect is identical to that of the four assertions listed earlier β except that warn is used instead of die. So it's the same energy, just less fatal. Soft launch of a failure, if you will π
.
π Progress Bars π
You can drop a smart comment on the same line as any of the following types of Perl loop:
foreach my VAR ( LIST ) { ### Progressing... done
for my VAR ( LIST ) { ### Progressing... done
foreach ( LIST ) { ### Progressing... done
for ( LIST ) { ### Progressing... done
while (CONDITION) { ### Progressing... done
until (CONDITION) { ### Progressing... done
for (INIT; CONDITION; INCR) { ### Progressing... done
In every one of these cases, the module animates the comment, making the dots extend from the left text, reaching the right text on the last iteration. So satisfying. So cinema. π¬
But for "open ended" loops (like while and C-style for loops), the dots will never reach the right text, and their progress slows down as the number of iterations increases. She's doing her best, okay?! π
For example, a smart comment like:
for (@candidates) { ### Evaluating... done
would be animated in the following sequence (which would appear sequentially on a single line, rather than on consecutive lines β important distinction bestie):
Evaluating done
Evaluating...... done
Evaluating............. done
Evaluating................... done
Evaluating..........................done
The module animates the first sequence of three identical characters in the comment, provided those characters are followed by a gap of at least two whitespace characters. So yes, you can absolutely specify different types of progress bars. Example:
for (@candidates) { ### Evaluating::: done
or:
for (@candidates) { ### Evaluating=== done
or:
for (@candidates) { ### Evaluating||| done
Now here's where it gets good. If the characters to be animated are immediately followed by other non-whitespace characters before the gap, then those other non-whitespace characters are used as an "arrow head" or "leader" and get pushed right by the growing progress bar. Like:
for (@candidates) { ### Evaluating===| done
which would animate like so:
Evaluating| done
Evaluating=====| done
Evaluating============| done
Evaluating==================| done
Evaluating==========================done
And if a percentage character (%) appears anywhere in the comment, it gets replaced by the percentage completion. Behold:
for (@candidates) { ### Evaluating [===| ] % done
animates like so:
Evaluating [| ] 0% done
Evaluating [===| ] 25% done
Evaluating [========| ] 50% done
Evaluating [============| ] 75% done
Evaluating [=================] 100% done
And if the % is in the "arrow head", it moves with the progress bar. So:
for (@candidates) { ### Evaluating |===[%] |
would be animated like so:
Evaluating |[0%] |
Evaluating |=[25%] |
Evaluating |========[50%] |
Evaluating |===============[75%] |
Evaluating |===========================|
For "open-ended" loops, though, the percentage completion is unknown β so the module replaces each % with the current iteration count instead. For example:
while ($next ne $target) { ### Evaluating |===[%] |
would animate like so:
Evaluating |[0] |
Evaluating |=[2] |
Evaluating |==[3] |
Evaluating |===[5] |
Evaluating |====[7] |
Evaluating |=====[8] |
and bestie, that is not the end of this page β there's more coming, so don't go anywhere, we're only getting started πβ¨
so like, your bar comes out looking something like this:
Evaluating |======[11] |
and bestie, before you come for the numbering β it is not sequential up there and that is on purpose π it's the "hurry up and slow down" algorithm doing its little dance, and the whole point of it is that open-ended loops can never actually reach the right-hand side. self-control, we love to see it. π
now for the glow-up special case β¨ if you draw the progress bar as two pairs of identical brackets:
for (@candidates) { ### Evaluating: [][]
for (@candidates) { ### Evaluating: {}{}
for (@candidates) { ### Evaluating: ()()
for (@candidates) { ### Evaluating: <><>
then the bar just grows by repeating bracket pairs, like:
Evaluating: [
Evaluating: []
Evaluating: [][
Evaluating: [][]
Evaluating: [][][
etc. and so on forever, she just keeps stacking them π§±β¨
and p.s. β progress bars don't have to have an animated component at all, no cap. they can simply report the loop's progress numerically:
for (@candidates) { ### Evaluating (% done)
which would animate β and heads up, all on the same line:
Evaluating (0% done)
Evaluating (25% done)
Evaluating (50% done)
Evaluating (75% done)
Evaluating (100% done)
π°οΈ TIME-REMAINING ESTIMATES π°οΈ
okay so when you use a progress bar with a for loop, the module is lowkey spying on how long each iteration takes and it uses that to estimate how much time the whole loop is gonna need. main character behaviour honestly π«Ά
normally you don't see that estimate β it stays quiet unless the estimate gets big enough that you genuinely deserve to know. specifically: the estimate shows up if, after five seconds, the time remaining exceeds ten seconds. which, translated to bestie-speak, means a time-remaining estimate gets shown if the module pegs a for loop that's probably gonna run more than 15 seconds total. example time:
for (@seven_samurai) { ### Fighting: [||| ]
fight();
sleep 5;
}
would animate like this:
Fighting: [ ]
Fighting: [|||| ]
Fighting: [||||||||| ] (about 20 seconds remaining)
Fighting: [|||||||||||||| ] (about 20 seconds remaining)
Fighting: [|||||||||||||||||| ] (about 10 seconds remaining)
Fighting: [||||||||||||||||||||||| ] (less than 10 seconds remaining)
Fighting: [|||||||||||||||||||||||||||]
and the precision of that reported time-remaining estimate? deliberately vague π mostly so it can't be annoyingly wrong. honestly, iconic design choice.
π©Ί DIAGNOSTICS π©Ί
in a sense, literally everything this module does is a diagnostic. everything. and every comment that prints anything prints it to STDERR.
but the module itself? only one diagnostic, one single diva:
"Incomprehensible arguments: %s in call to 'use Smart::Comments"β you loaded the module and handed it an argument that wasn't three-or-more#'s. arguments like'###','####','#####', etc. are the only ones the module accepts. anything else and she's like... no. π
βοΈ CONFIGURATION AND ENVIRONMENT π±
Smart::Comments can make use of an environment variable from your shell: Smart_Comments. you can set this variable either to a true/false value (i.e. 1 or 0) or with the same arguments you'd pass on the use line when loading the module (see "INTERFACE" if you skipped ahead, bestie).
here's the rundown, vibe-checked:
$ENV{Smart_Comments}set to1βΆ equivalent touse Smart::Comments;$ENV{Smart_Comments}set to0βΆ equivalent tono Smart::Comments;$ENV{Smart_Comments}set to'###:####'βΆ equivalent touse Smart::Comments qw(### ####);$ENV{Smart_Comments}set to'### ####'βΆ equivalent touse Smart::Comments qw(### ####);
to actually switch on the Smart_Comments environment variable, you need to load the module with the -ENV flag:
use Smart::Comments -ENV;
and no, you're not locked in β you can still specify other arguments in the use statement:
use Smart::Comments -ENV, qw(### #####);
in that case the contents of the environment variable replace the -ENV in the argument list. swap, slay. β¨
π¦ DEPENDENCIES π¦
the module requires these modules, no substitutions:
Filter::SimpleversionList::UtilData::DumperText::Balanced
π INCOMPATIBILITIES π
none reported π and honestly this module is probably even relatively safe sitting next to other Filter::Simple modules, since it's super specific and real limited in what it filters. picky in a good way.
π BUGS AND LIMITATIONS π
no bugs have been reported.
that said, this module has the usual limitations of source filters β i.e. it looks smarter than it is π (we've all been there).
please report any bugs or feature requests to bug-smart-comments@rt.cpan.org, or through the web interface at <http://rt.cpan.org>.
ποΈ REPOSITORY ποΈ
<https://github.com/neilb/Smart-Comments>
go star it, bestie, it's free β
π AUTHOR π
Damian Conway <DCONWAY@cpan.org>
(absolute legend, behaving accordingly)
βοΈ LICENCE AND COPYRIGHT βοΈ
Copyright (c) 2005, Damian Conway <DCONWAY@cpan.org>. All rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
π¨ DISCLAIMER OF WARRANTY π¨
bestie this next bit is ALL CAPS because it means it. do not skip, do not skim, it is legally required and it is unhinged on purpose:
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
and that's the whole page, bestie!! π this version of Smart::Comments(3pm) came to you straight out of perl v5.36.0, dated 2022-10-13, so if you're reading a different build just know your numbers might be slightly off. now go put some ### in your loops and watch the pretty bars. mwah π
ππ¦
π¦ where this page comes from
- ubuntu noble: libsmart-comments-perl 1.06-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libsmart-comments-perl 1.06-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libsmart-comments-perl 1.06-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms