Smart::Comments(3pm)

πŸ“¦
version 1.06 Β· 5 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– 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 the LABEL is any sequence of characters up to the first colon, and the EXPRESSION is 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 β€” the EXPRESSION is 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... β€” the TEXT is 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 to 1 ⟢ equivalent to use Smart::Comments;
  • $ENV{Smart_Comments} set to 0 ⟢ equivalent to no Smart::Comments;
  • $ENV{Smart_Comments} set to '###:####' ⟢ equivalent to use Smart::Comments qw(### ####);
  • $ENV{Smart_Comments} set to '### ####' ⟢ equivalent to use 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::Simple
  • version
  • List::Util
  • Data::Dumper
  • Text::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)


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