Devel::Comments(3pm)
πΈ NAME πΈ
Devel::Comments β debug with executable smart comments to logs π
(Yeah bestie, this is the Devel::Comments(3pm) page from the User Contributed Perl Documentation. Buckle up.)
β¨ VERSION β¨
This doc describes Devel::Comments version 1.1.4 π
π SYNOPSIS π
use Devel::Comments; # acts just like Smart::Comments
# Dumps...
my $scalar = 42;
### $scalar # prints to STDERR:
### $my_scalar: 42
### @array # dumps more complex
### $HoHoA # data structures, too
### Just in the neighborhood # prints literal message
# Level control...
use Devel::Comments '###'; # only activate level 3
### $scalar # this prints
#### $scalar # this doesn't
# Output control...
use Devel::Comments *STDOUT; # prints to STDOUT instead
use Devel::Comments \*FH; # prints to some FH
use Devel::Comments $fh; # prints to some $fh
use Devel::Comments ({ # hashref calling syntax
-file => 'my.log', # opens my.log and prints to it
});
# Assertions...
my ($x, $y) = 1, 0;
### check $x == $y # simulates warning and dumps info
### insist $x == $y # dumps and dies
# Progress bars...
for my $i (0..1e6) { ### Working===[%] done
do_something_expensive_with($i);
}
π¦ DESCRIPTION π¦
I get the feeling that the computer just skips over all the comments. -- a grad student
Not me reading this and feeling seen π
Devel::Comments is a source filter for your Perl code, and it's meant to be used only during development, okay? Specially-formatted 'smart' comments get replaced by actual executable code that dumps variables to screen or to file, shows loop progress bars, or enforces conditions. And the iconic part? You can disable all of these smart comments at once by just commenting out the use Devel::Comments line β and boom, they go right back to being simple, dumb comments. Your debugging code can literally just stay in place, guaranteed harmless, waiting for the next development cycle. Main character energy fr fr. π
Devel::Comments is a fork of Smart::Comments; the current intention is to add new features without breaking backward compatibility. Version 1.1.2 implements the 'any filehandle' feature, which lets smart output go to any filehandle opened for writing. You may instead pass in a filename, which DC will open for you. Future plans include extended calling syntax, numerical level enabling, improved progress bars, dump method callback, and execution of arbitrary code. Bugs raised against Smart::Comments 1.0.4 will be fixed in DC. πͺ
π INTERFACE π
There are two main parts to the DC interface: arguments passed on the use line; and 'smart' comments, which are specially-formatted comments introduced by three or more octothorpes, like '###', '####', or even '########'. Use-line arguments may also be passed in an environment variable.
DC provides no run-time public variables, functions, routines, or methods. DC is a source filter and does all its work at "compile-time". (Some DC routines are called at run-time from within replacement code previously filtered in.)
π The Use Line π
Most setup happens when the module is loaded via use Devel::Comments. If you call it with vanilla Smart::Comments arguments, DC will behave the same β it's a drop-in replacement, no cap. Backwards compatibility to Smart::Comments 1.0.4 is promised through DC 1.x.x.
Smart::Comments required arguments to be passed, in any order, as one flat list. While that's convenient for a small number of restricted-value arguments, it may "getcha" when you try it with many arguments whose values are unrestricted. This "free-form" calling syntax doesn't even have the security of positional parameters π¬
While every attempt will be made to interpret a flat list correctly, we will make a transition to named parameters as elements of a hash reference. Devel::Comments users are encouraged to use this newer calling syntax. Slay.
Following sections are headed by the appropriate hashref key, which always begins with a leading dash. NOTE: This early version 1.1.2 does not yet implement hashref calling syntax for parameters other than -filename. Other sections are headed by the hashref keys that will name their parameters. If the named parameter is unimplemented, you can still pass the argument in the flat list.
π -fh
named parameter syntax unimplemented
Example arguments: *STDOUT, "\*FH", $fh
Accepts an open, writable filehandle (typeglob or object) as an argument. Caller must do whatever is needed to manage that filehandle, like opening it (but probably not closing it).
Value must be acceptable as a filehandle:
$fh # indirect filehandle (perhaps IO::File object); recommended.
\*FH # reference to a typeglob
*FH # typeglob
"FH" # please don't do this; probably won't work as expected.
Except for *STDOUT you should probably avoid the typeglob notation. (No need to specify *STDERR explicitly; it's the default.) DC will try to work with a typeglob but there are risks. You'd better localize the typeglob; a lexical may not work. (See "Perl Cookbook Recipie 7.16".) Passing a string will probably fail.
See also "perldoc perlopentut".
Note that, effectively, modules are used within a BEGIN block. Therefore, your filehandle must be opened within a BEGIN block prior to the use line. If caller needs to do anything else with that filehandle, you might as well store it in a package variable (since source filtering is global anyway). Do not enclose the open and the use line in the same BEGIN block.
The filehandle must be opened, obviously, in some writable mode.
BEGIN { # get $::fh open early enough
my $filename = 'my.log';
open my $::fh, '>', $filename
or die "Couldn't open $filename to write", $!;
}
use Devel::Comments $::fh;
{...} # do some work
### $some_variable
print {$::fh} 'Some message...'; # do something else with $::fh
π -file
flat list parameter syntax unimplemented
Example arguments: '/var/my.log', "$0.log", 'ziggy.txt'
Value can be any filename or path, relative or fully qualified. The file will be created if it doesn't exist, truncated by default, opened for writing, and set to autoflush. All directory components must exist. (So like, don't come crying to me when the dir isn't there, bestie. π)
Until your entire program ends, there's no way to be sure that caller won't come into scope (say, a sub called from some other script or module). So DC can't do an explicit close(). That shouldn't be a problem, since perl will close the filehandle when the program terminates. If you need to do something differently, supply a filehandle and manage it yourself.
You may, in an upcoming version, pass a filename as a flat list argument. There's an issue here in that a filename might be just about any string; if you've chosen a peculiar filename such as '###' or '-ENV', there's going to be confusion. For now, this is unimplemented.
π -level
named parameter syntax unimplemented numerical levels unimplemented
Devel::Comments accepts arguments like '###', '####', and so forth. If none are given, then all comments introduced with 3 or more octothorpes are considered smart. Otherwise, only those comments introduced with a matching quantity are smart:
use Devel::Comments '###', '#####';
### This is smart.
#### This is dumb.
##### This is also smart.
Soon, you will be able to pass an integer or a list of integers:
use Devel::Comments ({-level => [3, 5] });
### This is smart.
#### This is dumb.
##### This is also smart.
But not quite yet. π
A level of 1 or 2 simply doesn't work. So don't do that.
π -env
named parameter syntax unimplemented
Example: "use Devel::Comments -ENV;"
Yet another way of specifying arguments (besides as a list or hashref in the use line) is to pass them in the environment variable $ENV{Devel_Comments}. But to enable this, you must pass "-ENV" in the use line or define "-env" in a hashref passed in the use line.
See "CONFIGURATION AND ENVIRONMENT".
Don't try to pass a hashref inside of the environment variable; you won't like the result. π
πΈ Smart Comments Format πΈ
In some small way, smart comments comprise an alternate language embedded within Perl. If you don't have any smart comments in your code, Devel::Comments, like Smart::Comments before it, will do essentially nothing. If you disable Devel::Comments (see "DISABLING"), then smart comments are guaranteed to do nothing at all, since they're then interpreted by perl as plain old dumb comments. Periodt.
All smart comments, without exception, are introduced by a series of three or more octothorpes: '###' at a minimum. This is not likely to change; the '##' sequence is used by Perl::Tidy to signal the end of lengthy constructs.
Aspects of this miniature language-within-a-language now include introducers, messages, dumps, assertions, and progress bars. Extensions are planned. β¨
π Introducers
A basic smart comment is any line beginning with '###':
### This comment is smart at debug level 3.
This is considered a level 3 comment; it will only be active if level 3 is enabled by one means or another. More octothorpes increase the debug level:
##### This comment is smart at debug level 5.
The number of debugging levels is essentially unlimited; so introducers may be of any length. However, this rapidly becomes unwieldy. π
unimplemented: An alternate means of specifying the debug level is:
###4 This comment is smart at debug level 4.
Every introducer ends with a space or tab ("m/[ \t]/"); anything before the first white character is considered part of the introducer.
unimplemented: An introducer ending in an ampersand ("&") marks raw Perl code; in effect, the introducer is simply stripped off if it is at an enabled debug level:
###& push @zoo, $monkey # Put the monkey in the zoo at debug level 3.
Note that, with the exception of progress bars, a smart comment must begin its line; that is, only whitespace can intervene between an introducer and the preceeding newline. Trailing smart comments may be a future feature.
π Messages
Any smart comment not matching other patterns will be dumped as is:
### Hello, World!
In a message, "<now>", "<time>", or "<when>" is replaced by a timestamp (same timestamp for all three). Also, "<here>", "<place>", or "<where>" is replaced by what Damian Conway calls a "spacestamp" similar to what you see by default in die() or warn():
### Here <here>
### Now <now>
prints something like:
### Here "util/demo.pl", line 71
### Now Fri Aug 6 07:50:51 2010
okay so lowkey the vibe here is: no colon ever follows Here or Now. Like, any text would do just fine as a label, but no text at all β just the bare <now> sitting there all alone β gets confused and does not work. And yeah, that's considered a bug, not a feature. π
### <here> <now>
β¦ this one? absolutely works fine and is genuinely an excellent way to kick off a logging session. iconic behavior honestly. β¨
Original SC documentation was out here requiring that such plain text messages be terminated with a simulated elipsis:
### This text is printed...
β¦ but bestie, that was not actually enforced and it is not required in DC. so don't stress about it. π
π«Ά Dumps
Any scalar, array, hash; a reference to any of these; or honestly any more complex structure β you can dump it just by typing the variable:
### $dump_me
The dump gets labeled with the variable name, sigil and all. but you can also supply your own label if you're feeling custom:
### Working tree: $tree
The automatic labeling is the real driving force behind DC though, fr fr. Even dark magiks involving Pad::Walker and rooting around in symbol tables has trouble getting the right name for a variable and its value. The only place it's convenient to do this is in the same scope as the variable itself β hence, a source filter. iykyk. π§
You can dump an arbitrary expression too:
my $index = 8;
### Add five: $index + 5
prints:
### Add five: 13
However β this will not work if you don't supply your own label. no label, no vibes. π
Beware side effects:
my @array = ( 1, 2, 3 );
say @array;
### Pop: pop @array
say @array;
prints:
123
### Pop: 3
12
If you don't want the verbosity of <here>, try:
#### At: __LINE__
π Assertions
Seven keywords cannot be used as labels. If one of them is used to label an expression, it gets evaluated in boolean context and, if the expression is true, nothing is output at all. But if the expression is false, a message announcing the failure gets output, similar to warn():
### check: 1 == 0
prints something like:
### 1 == 0 was not true at util/demo.pl line 92.
The assertions:
### check: BOOL
### confirm: BOOL
### verify: BOOL
β¦ simulate warn() on failure, although the smart output goes to the chosen output file or filehandle β not necessarily STDERR. heads up bestie. π
### assert: BOOL
### ensure: BOOL
### insist: BOOL
### require: BOOL
β¦ print the same message on failure, then call die().
Note: these seven keywords are supported in the current version of DC but all exceptcheckandassertare deprecated. so plan accordingly. π
π Progress Bars
Only in these can a smart comment appear on the same line with Perl code:
for (@candidates) { ### Evaluating |===[%] |
prints, in succession:
Evaluating |[0%] |
Evaluating |=[25%] |
Evaluating |========[50%] |
Evaluating |===============[75%] |
Evaluating |===========================|
At each step, the previous bar is erased and overwritten by the next; when the loop completes, the last bar is erased, too. poof. gone. π¦
There are a great number of possible progress bar formats and they are very clever indeed. There is, however, among developers polled, almost no interest in them; and they are difficult to support. It's not clear that they're truly useful in debugging. So, although they are supported in the current DC release, they likely will be deprecated or replaced by a different loop reporting function.
Both Vanilla and DC animate the progress bar by printing the "\r" character and wiping the line with spaces. This is unchanged when smart output goes to a disk file. Depending on your method of reading that file, you may see multiple lines or nothing at all. But if, for some reason, the loop aborts, you may see how far along it got. π
If you want to experiment with progress bars, you may want to look at the Smart::Comments documentation. If you like them, please be sure to indicate your support. π«Ά
π DISABLING
Source filters are a bit dicey; the saving grace of DC (and its parent) is that it can be disabled easily and completely; all specially-formatted smart comments return to being plain old dumb comments, guaranteed not to interfere with normal execution:
#use Devel::Comments; # disable in production
### assert 0 == 1 # does nothing at all
There are other methods of disabling DC.
If you write:
use Devel::Comments -ENV; # heed environment variable
β¦ then DC will only be active if $ENV{Devel_Comments} is set, possibly to some other DC use-line arguments or mererly to 1. If it is set to 0 or deleted, then DC is disabled.
DC can be restricted to a certain span of code. If you write:
### Hello, Andy!
use Devel::Comments;
### Hello, Bob!
no Devel::Comments;
### Hello, Cindy!
then Bob will be greeted but not Andy or Cindy. Note that docs for Filter::Simple suggest other possible text for the statement that terminates filtering; these others don't seem to work, so don't do that. π
You might load DC in the shell invocation:
$ perl -d:Comments myscript.pl
Next time, don't do that and DC won't load, of course. This loading method is untested but if there are requests for it, I'll work it up. π
Any given smart comment can be disabled by changing the introducer to a level that's disabled in the use line, or to an invalid introducer:
use Devel::Comments '###';
### grin
#### and
# ### bear
# ## it
prints:
### grin
β¨ HOW IT WORKS
Technically, arguments present on any use line are presented to a module's import() method. Devel::Comments uses Filter::Simple to do the heavy lifting; FS converts a call to Filter::Simple::FILTER into Devel::Comments::import().
All of the following code, to end of file or any no Devel::Comments line, is filtered. All smart comments (with correct introducers) are replaced by executable Perl code.
If you write something funky, like:
my $string = q{
bobby says
### think
};
β¦ then you are asking for trouble and will likely get it. π
my $string = q{\n bobby says\n ### think\n};
β¦ is perfectly safe and will be ignored by DC.
Dumps of complex structures are done by the venerable Data::Dumper. The output is cleaned up a bit before being printed; the all-important variable identifier is inserted.
π Scope, State, Output Regimes
DC may be called more than once in the same program, e.g., from two different loaded modules. As does vanilla SC, DC has effect until the end of the file or a no Devel::Comments line (which must be the first thing on its line). If used again, DC will parse the new use line and apply it to your source code from there on out.
This required no special logic in Vanilla; the filter is applied once per use and although multiple modules might call S::C routines from within filtered code, all output went to STDERR. But multiple uses of DC may choose different output regimes. So state information is stored for each caller.
If you supply a filehandle (other than STDOUT or STDERR), your (filtered) code will need that later to print smart output where you want it to go. If you supply a package variable as an indirect filehandle (such as $My::Module::fh), then all is well. If you supply a lexical ("my") variable, DC will still work, even after it goes out of scope in your package, because a reference is stored in DC's namespace. But by the same token, don't expect it to be garbage-collected. You may as well use a package "global" variable, since source filtering is pretty much a global operation anyway.
If you pass a filename but no filehandle, you'll get smart output but you won't have any way to write directly to the file (should you take that notion). Not recommended to open the file again within your script, although that might work.
π DIAGNOSTICS
Internal error: _get_outfh called with no or false arg. $!
Internal error: $caller_id not defined in %state_of. $!
Internal error: No output filehandle found in %state_of for $caller_id. $!
Internal error: -caller_id not passed in call to _init_state(). $!
Internal error: -outfh not passed in call to _init_state(). $!
You should never see any of these errors involving state maintenance. If you do, please contact the author with as much information as possible. π
Can't open $out_filename to write.
You passed in a filename that couldn't be written to. Check to see that all directory components of the path exist and that you have permission to write to the target file.
Filesystem IO error: Failed to print to output filehandle for $caller_id
Gee, that's funny. But if DC can't write to a filehandle you supplied, it's probably not something I can do anything about. Perhaps the disk is full or the socket is closed? Be sure you have opened the filehandle for writing in a BEGIN block prior to the use Devel::Comments; line. Check to see you can write to it.
Internal error: DATA. $!
You should never see this error either. If you do, please contact the author with as much information as possible.
### $assertion was not true
This is not a module error but smart output you generated. See "ASSERTIONS".
πΈ CONFIGURATION AND ENVIRONMENT
Devel::Comments can make use of an environment variable from your shell: Devel_Comments. This variable can be specified either with a true/false value (i.e. 1 or 0) or with the same arguments as may be passed on the use line when loading the module (see "INTERFACE"). The following table summarizes the behaviour:
- Value of
$ENV{Devel_Comments}:1β Equivalent Perl:use Devel::Comments; - Value of
$ENV{Devel_Comments}:0β Equivalent Perl:no Devel::Comments; - Value of
$ENV{Devel_Comments}:'###:####'β Equivalent Perl:use Devel::Comments qw(### ####); - Value of
$ENV{Devel_Comments}:'### ####'β Equivalent Perl:use Devel::Comments qw(### ####);
To enable the Devel_Comments environment variable, you need to load the module with the -ENV flag:
use Devel::Comments -ENV;
Note that you can still specify other arguments in the use statement:
use Devel::Comments -ENV, qw(### #####);
In this case, the contents of the environment variable replace the -ENV in the argument list.
π¦ DEPENDENCIES
The module requires the following modules:
Filter::Simpleversion.pmList::UtilData::DumperText::Balanced
π INCOMPATIBILITIES π
Okay so bestie, there's some drama with other modules, and you deserve to know about it before it jumps you.
- It's known that
IO::Capture::Tie_STDx0.05does not implement aTELL()method. That's a whole mess if smart output is being directed to a captured filehandle. The workaround? InstallIO::Capture::Tellfix, which ships right along with this distribution. π - It's not recommended to use DC in combination with other source filters. Justβ¦ don't. π«Ά
π BUGS AND LIMITATIONS π
Not me listing the flaws in my own fave module but here we are, transparency is the vibe:
Tellfixis ugly and it raises a warning under some circumstances. The intent is to move offIO::Capture::*altogether in favor ofTest::Trap; so this issue will not be fixed directly. It's giving "we're moving out, we're not repainting the walls." π- The current testing paradigm is flawed; it has too many dependencies, including perl
5.010. We ship with a cut-down"user"test suite, which should run fine under perl5.008; this is mostly a rehash of the originalSmart::Commentstest suite and doesn't fully exercise DC's new features. Those interested may want to run the full test suite found int/all/. - A number of features are marked as unimplemented. π
- Bugs outstanding against SC
1.0.4can be found at <https://rt.cpan.org/Dist/Display.html?Queue=Smart-Comments> and they are probably all present in this version of DC. You are welcome to relist against DC any that you find; but I will be working off that list, too. - Please report any bugs or feature requests to <https://rt.cpan.org/Public/Bug/Report.html?Queue=Devel-Comments> or email
"<XIONG@cpan.org>". These are welcome and will be acted upon. β¨
π TODO π
The glow-up list, fr fr:
- Argment passing will be made orthogonal, as much as possible. Arguments can be passed either as one flat list or as named elements of a single hashref.
- Debug levels passed numerically and numerical introducers.
- Invocation of client methods for dumping objects.
- Pass-through execution of arbitrary debugging code.
- Police up scraps of stuff currently left in caller's namespace. Store all state entirely within DC.
π THANKS π
Shoutout to the girlies who made this happen:
- Mike Stok
"<MIKESTOK@cpan.org>"for reporting RT#62599 and fixing it. π - Kevin Ryde for reporting RT#69712 and reviving the project. π¦
β¨ AUTHOR β¨
Xiong Changnian "<XIONG@cpan.org>"
π LICENCE AND COPYRIGHT π
Copyright (c) 2010, 2011, Xiong Changnian "<XIONG@cpan.org>". All rights reserved.
Based almost entirely on Smart::Comments, 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 π¨
Okay bestie, this part is legally required to be in all caps, so I'm not yelling at you, the lawyers are. Read it, it's important. π
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 one's Devel::Comments(3pm), page from perl v5.42.0, dated 2025-07-25 β go forth and comment your little heart out. Slay. π
β¨
π¦ where this page comes from
- fedora 43: perl-Devel-Comments 1.1.4-39.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms