NAME
Perl::Critic::Policy::ValuesAndExpressions::RequireConsistentQuoting - Use consistent and optimal quoting
VERSION
version v0.1.4
SYNOPSIS
# Bad examples:
my $greeting = 'hello'; # use double quotes for simple strings
my @words = qw{word(with)parens}; # use qw[] for unbalanced content
my $text = qq(simple); # use "" instead of qq()
my $file = q!path/to/file!; # use "" instead of q()
use Config 'arg1', 'arg2'; # simple strings should use qw()
use lib ( "$HOME/perl" ); # complex expressions need no
# parentheses
# Good examples:
my $greeting = "hello"; # double quotes for simple strings
my @words = qw[ word(with)parens ]; # optimal delimiter choice
my $text = "simple"; # "" preferred over qq()
my $file = "path/to/file"; # "" reduces punctuation
use Config qw( arg1 arg2 ); # simple use arguments use qw()
use lib "$HOME/perl"; # interpolation uses normal rules
DESCRIPTION
This policy enforces consistent quoting to improve code readability and maintainability. It applies three simple rules:
Rule 1: Reduce punctuation
Prefer fewer characters and simpler syntax. Prefer real quotes over quote-like operators when possible.
# Good
my $text = "hello world"; # "" preferred over qq()
my $literal = 'contains$literal'; # '' preferred over q()
my $path = "path/to/file"; # simple quotes reduce punctuation
# Bad
my $text = qq(hello world); # unnecessary quote operator
my $literal = q(contains$literal); # unnecessary quote operator
my $path = q!path/to/file!; # unnecessary quote operator
Rule 2: Prefer interpolated strings
If it doesn't matter whether a string is interpolated or not, prefer the interpolated version (double quotes).
# Good
my $name = "John"; # simple string uses double quotes
my $email = 'user@domain.com'; # literal @ uses single quotes
my $var = 'Price: $10'; # literal $ uses single quotes
# Bad
my $name = 'John'; # should use double quotes
Rule 3: Use bracket delimiters in preference order
If the best choice is a quote-like operator, prefer ()
, []
, <>
, or {}
in that order.
# Good
my @words = qw( simple list ); # () preferred when content is simple
my @data = qw[ has(parens) ]; # [] optimal - handles unbalanced ()
my $cmd = qx( has[brackets] ); # () optimal - handles unbalanced []
my $text = q( has<angles> ); # () optimal - handles unbalanced <>
# Bad - exotic delimiters
my @words = qw/word word/; # should use qw()
my $path = q|some|path|; # should use ""
my $text = qq#some#text#; # should use ""
Special Case: Use and No statements
Use and no statements have special quoting requirements for their import lists. Both use
and no
statements follow identical rules:
Modules with no arguments or empty parentheses are acceptable
Single version numbers (e.g.,
1.23
,v5.10.0
) are exempt from all rulesFat comma (
=>
) arguments should have no parentheses for readabilityComplex expressions (variables, conditionals, structures) should have no parentheses
Arguments requiring interpolation follow normal string quoting rules individually
Simple string arguments without interpolation should use
qw( )
with parentheses only
This design promotes readability whilst maintaining compatibility with perlimports.
# Good - basic cases
use Foo; # no arguments
use Bar (); # empty parentheses
use Baz 1.23; # version numbers exempt
no warnings; # no statements follow same rules
# Good - fat comma arguments (no parentheses)
use Data::Printer
deparse => 0,
show_unicode => 1,
class => { expand => "all" };
# Good - complex expressions (no parentheses)
use Module $VERSION;
use Config $DEBUG ? "verbose" : "quiet";
use Handler { config => "file.conf" };
# Good - interpolation cases (normal string rules)
use lib "$HOME/perl", "/usr/lib"; # interpolation prevents qw()
no warnings "$category", "another"; # applies to no statements too
# Good - simple strings use qw()
use Foo qw( arg1 arg2 arg3 ); # multiple simple arguments
no warnings qw( experimental uninitialized );
# Bad - incorrect quoting
use Foo 'single_arg'; # single quotes should use qw()
use Bar "arg1", "arg2"; # simple strings need qw()
use Baz qw[ arg1 arg2 ]; # qw() must use parentheses only
use Qux ( key => "value" ); # fat comma needs no parentheses
use Quux ( $VERSION ); # complex expressions need no
# parentheses
Special Case: Newlines
Strings containing newlines do not follow the rules. But note that outside of a few very special cases, strings with literal newlines are not a good idea.
# Allowed
my $text = qq(
line 1
line 2
);
RATIONALE
Minimising escape characters improves readability and reduces errors
Simple quotes are preferred over their
q()
andqq()
equivalents when possibleDouble quotes are preferred for consistency and to allow potential interpolation
Many years ago, Tom Christiansen wrote a lengthy article on how perl's default quoting system is interpolation, and not interpolating means something extraordinary is happening. I can't find the original article, but you can see that double quotes are used by default in The Perl Cookbook, for example.
Only bracket delimiters should be used (no exotic delimiters like
/
,|
,#
, etc.)Optimal delimiter selection reduces visual noise in code
AFFILIATION
This Policy is part of the Perl::Critic::PJCJ distribution.
CONFIGURATION
This Policy is not configurable except for the standard options.
EXAMPLES
String Literals
# Bad
my $greeting = 'hello'; # Rule 2: should use double quotes
my $email = "user@domain.com"; # Rule 2: should use single quotes
# (literal @)
my $path = 'C:\Program Files'; # Rule 2: should use double quotes
# Good
my $greeting = "hello"; # double quotes for simple strings
my $email = 'user@domain.com'; # single quotes for literal @
my $path = "C:\\Program Files"; # double quotes handle backslashes
Quote Operators
# Bad
my $simple = q(hello); # Rule 1: should use ''
my $text = qq(hello); # Rule 1: should use ""
my @words = qw/one two/; # Rule 3: should use qw( )
my $cmd = qx|ls|; # Rule 3: should use qx( )
# Good
my $simple = 'hello$literal'; # single quotes for literal content
my $text = "hello"; # double quotes preferred
my @words = qw( one two ); # bracket delimiters only
my $cmd = qx( ls ); # bracket delimiters only
Optimal Delimiter Selection
# Bad - unbalanced delimiters
my @list = qw(word(with)parens); # Rules 1, 3: unbalanced () in content
my $cmd = qx[command[with]brackets]; # Rules 1, 3: unbalanced [] in content
my $text = q{word{with}braces}; # Rules 1, 3: unbalanced {} in content
# Good - balanced delimiters
my @list = qw[ word(with)parens ]; # [] handles parentheses in content
my $cmd = qx( command[with]brackets ); # () handles brackets in content
Complex Content
# When content has multiple quote types, quote-like operators may be needed
my $both = qq(has 'single' and "double" quotes); # qq() handles both
# quote types cleanly
Use and No Statement Examples
# Bad
use Foo 'single_arg'; # single quotes should use qw()
use Bar "arg1", "arg2"; # simple strings need qw()
use Baz qw[ arg1 arg2 ]; # qw() must use parentheses only
use Qux ( key => "value" ); # fat comma should have no parentheses
use Quux ( $VERSION ); # complex expressions need no
# parentheses
no warnings ( "experimental" ); # simple strings should use qw()
# Good
use Foo; # no arguments
use Bar (); # empty parentheses
use Baz 1.23; # version numbers exempt
use Qux qw( single_arg ); # simple string uses qw()
use Quux qw( arg1 arg2 arg3 ); # multiple simple arguments
no warnings qw( experimental uninitialized ); # no statements follow same
# rules
# Fat comma examples (no parentheses)
use Data::Printer
deparse => 0,
show_unicode => 1;
use Config
key => "value",
another_key => { nested => "structure" };
# Complex expression examples (no parentheses)
use Module $VERSION; # variable argument
use Config $DEBUG ? "verbose" : "quiet"; # conditional expression
use Handler { config => "file.conf" }; # hash reference
# Interpolation examples (normal string rules apply)
use lib "$HOME/perl", "/usr/lib"; # interpolation prevents qw()
use lib "$x/d1", "$x/d2"; # both strings need interpolation
use lib "$HOME/perl", "static"; # mixed interpolation uses double
# quotes
no warnings "$category", "another"; # no statements handle
# interpolation too
METHODS
supported_parameters
This policy has no configurable parameters.
violates
The main entry point for policy violation checking. Uses a dispatch table to route different quote token types to their appropriate checking methods. This design allows for efficient handling of the six different PPI token types that represent quoted strings and quote-like operators.
would_interpolate
Determines whether a string would perform variable interpolation if placed in double quotes. This is critical for deciding between single and double quotes - strings that would interpolate variables should use single quotes to preserve literal content, while non-interpolating strings should use double quotes for consistency.
Uses PPI's authoritative parsing to detect interpolation rather than regex patterns, ensuring accurate detection of complex cases like literal variables.
would_interpolate_from_single_quotes
Tests whether a string from single quotes would interpolate if converted to double quotes. This specialised version handles the challenge that PPI provides decoded string content rather than the original source text.
When checking single-quoted strings, PPI's string()
method returns the decoded content. For example, the source 'price: \\$5.00'
becomes 'price: \$5.00'
in the content (with one backslash). To test interpolation properly, this method reconstructs what the original escaping would have been by re-escaping backslashes and apostrophes according to single-quote rules.
This ensures accurate detection of whether converting a single-quoted string to double quotes would introduce unintended variable interpolation.
delimiter_preference_order
Establishes the preference hierarchy for bracket delimiters when multiple options handle the content equally well. The policy prefers delimiters in this order: ()
> []
> <>
> {}
.
This ordering balances readability and convention - parentheses are most familiar and commonly used, while braces are often reserved for hash references and blocks.
parse_quote_token
Extracts delimiter and content information from quote-like operators such as qw{}
, q{}
, qq{}
, and qx{}
. Handles both bracket pairs (where start and end delimiters differ) and symmetric delimiters (where they're the same).
This parsing is essential for delimiter optimisation, as it separates the operator, delimiters, and content for independent analysis.
find_optimal_delimiter
Determines the best delimiter choice for a quote-like operator by analysing the content for balanced delimiters. Implements the core logic for Rules 1 and 3: choose delimiters that handle unbalanced content gracefully and prefer bracket delimiters.
Only considers bracket delimiters ()
, []
, <>
, {}
as valid options, rejecting exotic delimiters like /
, |
, #
. When multiple delimiters work equally well, uses the preference order to break ties.
check_delimiter_optimisation
Validates that quote-like operators use optimal delimiters according to Rules 1 and 3. This method coordinates parsing the current token and finding the optimal alternative, issuing violations when the current choice is suboptimal.
Acts as a bridge between the parsing and optimisation logic, providing a clean interface for the quote-checking methods.
check_single_quoted
Enforces Rules 1 and 2 for single-quoted strings: prefer double quotes for simple strings unless the content contains literal $
or @
characters that shouldn't be interpolated, or the string contains double quotes that would require special handling.
Also detects when q()
operators would be better than single quotes for complex content, promoting cleaner alternatives.
check_double_quoted
Validates double-quoted strings to ensure they genuinely need interpolation. Suggests single quotes when the content contains only literal $
or @
characters with no actual interpolation, as this indicates the developer intended literal content.
This reduces unnecessary complexity and makes the code's intent clearer.
check_q_literal
Enforces Rules 1 and 3 for q()
operators. First ensures optimal delimiter choice, then evaluates whether simpler quote forms would be more appropriate.
Allows q()
when the content has both single and double quotes (making it the cleanest option), but suggests simpler alternatives for basic content that could use ''
or ""
.
check_qq_interpolate
Enforces Rules 1 and 3 for qq()
operators. First ensures optimal delimiter choice, then determines whether simple double quotes would suffice.
The policy prefers ""
over qq()
when the content doesn't contain double quotes, as this reduces visual noise and follows common Perl conventions.
check_quote_operators
Handles qw()
and qx()
operators, focusing purely on delimiter optimisation according to Rules 1 and 3. These operators don't have simpler alternatives, so the policy only ensures they use the most appropriate delimiters to handle unbalanced content gracefully.
check_use_statement
Checks quoting consistency in use
and no
statements. Implements comprehensive argument analysis to enforce appropriate quoting based on argument types:
Version numbers are exempt from all quoting rules
Fat comma arguments should have no parentheses for readability
Complex expressions should have no parentheses to reduce visual noise
Arguments requiring interpolation follow normal string quoting rules
Simple string arguments should use
qw()
with parentheses only
This promotes consistency and clarity whilst supporting modern Perl idioms and maintaining compatibility with tools like perlimports.
_analyse_argument_types
Analyses use/no statement arguments to classify them into different types: fat comma operators, complex expressions, version numbers, simple strings, and quote operators. This classification drives the quoting rule enforcement in check_use_statement
.
Also detects whether the original statement uses parentheses, which affects the violation messages for fat comma and complex expression cases.
_extract_use_arguments
Extracts and processes arguments from use/no statements, handling both bare arguments and those enclosed in parentheses. Skips whitespace, commas, and semicolons whilst preserving significant operators like fat comma (=>
).
Handles nested list structures by recursively extracting their contents, ensuring all argument types are properly identified for rule enforcement.
_extract_list_arguments
Recursively processes parenthesised argument lists within use/no statements. Handles complex nested structures including expressions, statements, and hash constructors whilst filtering out structural tokens that don't affect quoting decisions.
_summarise_use_arguments
Provides summary statistics about use/no statement arguments: counts string tokens, detects qw()
usage, and verifies that qw()
operators use parentheses rather than other delimiters. This information drives the violation logic in check_use_statement
.
AUTHOR
Paul Johnson <paul@pjcj.net>
COPYRIGHT
Copyright 2025 Paul Johnson.
LICENCE
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.