NAME
Marlin::Manual::BetterAttributes - better attributes with Marlin
DESCRIPTION
Towards the end of Marlin::Manual::Beginning, attribute options hashrefs were introduced. This manual page lists the various options available and when they might be useful.
The is Option
The is option is a shorthand for setting other options. Assuming your attribute is named "foo", then:
ro-
Setting
is => 'ro'is a shorthand forreader => 'foo'. This is Marlin's default anyway. rw-
Setting
is => 'rw'is a shorthand foraccessor => 'foo'. Marlin alternatively allows you to declare the attribute as"foo=="which has the same effect. rwp-
Setting
is => 'rwp'is a shorthand forreader => 'foo', writer => "_set_foo". Marlin alternatively allows you to declare the attribute as"foo="which has the same effect. lazy-
Setting
is => 'lazy'is a shorthand forlazy => true, and will also setbuilder => '_build_foo'unless the attribute has an existingbuilderordefaultoption. bare-
Setting
is => 'bare'does not do anything in itself, but allows you to override the default ofis => 'ro'.
For each of these values, Marlin::Util exports a constant allowing you to avoid quoting them.
Example: Bareword Constants
use Marlin::Util -all;
use Marlin
foo => { is => ro },
bar => { is => rw };
Documenting Attributes
The documentation option does nothing, but allows you to provide documentation for an attribute.
Example: Documenting Attributes
use Marlin::Util -all;
use Marlin
foo => { is => ro, documentation => "See Chapter 3" },
bar => { is => rw, documentation => "See Chapter 4" };
I cannot emphasize enough that this does nothing.
Options Affecting Constructor Behaviour
init_arg
The name of the argument passed to the constructor which will be used to initialize this attribute.
Example: Custom Initialization Argument
package Thing {
use Marlin foo => { init_arg => 'my_foo' };
}
my $thing = Thing->new( my_foo => 123 );
say $thing->foo;
Setting to an explicit undef prevents the constructor from initializing the attribute from the arguments passed to it.
Example: No Initialization Argument
package Thing {
use Marlin foo => { init_arg => undef };
}
# ERROR!
my $thing = Thing->new( foo => 123 );
required
If true, indicates that callers must provide a value for this attribute to the constructor. If false, indicates that it is optional.
Marlin alternatively allows you to declare an attribute with an exclamation mark. The following two examples are equivalent.
Example: Longhand
use Marlin::Util qw( ro rw true false );
use Marlin
foo => { is => ro, required => true },
bar => { is => ro, required => false };
Example: Shorthand
use Marlin qw( foo! bar! );
To indicate that the attribute is forbidden in the constructor, use a combination of init_arg => undef and a strict constructor.
undef_tolerant
If you set an attribute to undef_tolerant => true, and then try to initialized it to undef in the constructor, it will be treated as if you hadn't passed it to the constructor at all. See MooseX::UndefTolerant.
To make all attributes in your class or role undef tolerant, see Marlin::X::UndefTolerant.
Options Declaring Accessors Etc
reader
You can specify the name for a reader method:
Example: Custom Named Reader
use Marlin name => { reader => "get_name" };
If you use reader => 1 or reader => true, Marlin will pick a default name for your reader by adding "_get" to the front of attributes that have a leading underscore and "get_" otherwise.
writer
Like reader, but a writer method.
If you use writer => 1 or writer => true, Marlin will pick a default name for your writer by adding "_set" to the front of attributes that have a leading underscore and "set_" otherwise.
accessor
A combination reader or writer, depending on whether it's called with a parameter or not.
If you use accessor => 1 or accessor => true, Marlin will pick a default name for your writer which is just the same as your attribute's name.
clearer
Like reader, but a clearer method. A clearer deletes the value of an attribute so that the attribute is no longer considered to be set at all, not even set to false.
If an attribute has a lazy default or builder, after it has been cleared it will be reinitialized to the default value the next time you try to read it. If it had an eager default or builder, that will not happen.
If you use clearer => 1 or clearer => true, Marlin will pick a default name for your clearer by adding "_clear" to the front of attributes that have a leading underscore and "clear_" otherwise.
predicate
Like reader, but a predicate method, checking whether a value was supplied for the attribute. (It checks exists, not defined!)
If you use predicate => 1 or predicate => true, Marlin will pick a default name for your predicate by adding "_has" to the front of attributes that have a leading underscore and "has_" otherwise.
Lexical Accessors Etc
Marlin supports a number of options to keep your accessors truly private. (More so than just a leading "_".)
CodeRef Lexical Methods
You can specify a scalarref variable to install the reader into.
Example: Declaring a CodeRef Lexical Reader
use Marlin name => { reader => \( my $get_name ) };
The coderef won't be assessible outside the scope where you declared it, so presumably only within your class. (Assuming your class declaration is in its own scope, like in {...} or in its own file.) This prevents outside code from calling it.
This is equivalent to defining a reader like this.
Example: What is a CodeRef Lexical Reader?
# This is what Marlin is doing for you
my $get_name = sub ( $self ) {
...;
};
You can call your reader using this syntax:
Example: Using a CodeRef Lexical Reader
say $thingy->$get_name();
And in outside code, the $get_name variable won't exist, so it becomes a compilation error to even try to use it.
True Lexical Methods
From Perl v5.12.0 onwards, the following is also supported.
Example: Declaring a True Lexical Reader
use Marlin name => { reader => 'my get_name' };
This is equivalent to using lexical subs which were a feature introduced in Perl 5.18. (But yes, we support it from Perl 5.12!)
Example: What is a True Lexical Reader?
# This is what Marlin is doing for you
my sub get_name ( $self ) {
...;
}
You need to call true lexical readers like functions, not using the -> method syntax, unless you have a very recent version of Perl.
Example: Using a True Lexical Reader
say get_name( $thingy );
Perl v5.42.0 introduces a syntax for calling lexical subs as methods.
Example: Using a True Lexical Reader on Ultra-Modern Perl
say $thingy->&get_name();
If you attempt to use the 'my get_name' syntax on Perl versions older that 5.12, Marlin will make a best effort to do what you want. They will be installed as a normal sub in the caller package. (Note that the caller package might differ from the class currently being built, especially in the case of Marlin::Struct classes.) Marlin will attempt to clean them later with namespace::clean.
Attribute Default Values
builder, default, and lazy
The default can be set to a coderef or a non-reference value to set a default value for the attribute.
As an extension to what Moose and Moo allow, you can also set the default to a reference to a string of Perl code.
Example: Specifying Defaults With Quoted Perl Code
default => \'[]'
Alternatively, builder can be used to provide the name of a method to call which will generate a default value.
If you use builder => 1 or builder => true, Marlin will assume a builder name of "_build_" followed by your attribute name. If you use builder => sub {...} then the coderef will be installed with that name.
If you choose lazy, then the default or builder will be run when the value of the attribute is first needed. Otherwise it will be run in the constructor.
If you use lazy builders/defaults, readers/accessors for the affected attributes will be implemented in Perl rather than XS. This is a good reason to have separate methods for readers and writers, so that the reader can remain fast!
constant
Defines a constant attribute, effectively an attribute with a default that can never be changed.
Example: Constant Attributes
package Person {
use Marlin
...,
species => { constant => 'Homo sapiens' };
}
my $bob = Person->new( ... );
say $bob->species;
Constants attributes cannot have writers, clearers, predicates, builders, defaults, or triggers. They must be a simple non-reference value. They cannot be passed to the constructor. They can have a type constraint and coercion, which will be used once at compile time. They can have handles and handles_via, provided the delegated methods do not attempt to alter the constant.
These constant attributes are still intended to be called as object methods. Calling them as functions is not supported and even though it might sometimes work, no guarantees are provided that it will continue to work.
Example: Reading Constant Attributes
say $bob->species; # GOOD
say Person::species(); # BAD
If you want that type of constant, use the constant pragma.
Attribute Validation
isa
A type constraint for an attribute. We recommend the use of Types::Common as a type constraint library.
Example: Type Constraints
package Local::Location {
...;
}
package Local::Person {
use Types::Common -all;
use Marlin
name => { isa => Str },
age => { isa => Int },
place_of_birth => { isa => InstanceOf['Local::Location'] },
favourite_colour => { isa => Enum['blue', 'pink', 'black'] },
favourite_numbers => { isa => ArrayRef[Num] },
children => { isa => ArrayRef },
...;
}
Any type checks or coercions will force the accessors and writers for those attributes to be implemented in Perl instead of XS. This is a good reason to have separate reader and writer methods for attributes, because the readers don't need to care about type constraints, so can be faster.
Type::Tiny::Manual has more information about advanced uses of type constraints, such as:
Example: Advanced Type Constraints
age => { isa => Int->where( sub { $_ >= 0 } ) }
You can use isa => sub { ... } to write a custom type check. The coderef should either die or return false to indicate a failure.
If the type constraint is a string, Marlin will use dwim_type from Type::Utils to determine what you meant, falling back to assuming it was a class name. The previous example can be written as:
Example: Stringy Type Constraints
package Local::Person {
use Marlin
name => { isa => "Str" },
age => { isa => "Int" },
place_of_birth => { isa => "Local::Location" },
favourite_colour => { isa => "Enum['blue', 'pink', 'black']" },
favourite_numbers => { isa => "ArrayRef[Num]" },
children => { isa => "ArrayRef" },
...;
}
enum
You can use enum => ['foo','bar'] as a shortcut for isa => Enum['foo','bar']
Example: Using enum
package Local::Person {
use Types::Common -all;
use Marlin
name => { isa => Str },
age => { isa => Int },
place_of_birth => { isa => "Local::Location" },
favourite_colour => { enum => ['blue', 'pink', 'black'] },
favourite_numbers => { isa => ArrayRef[Num] },
children => { isa => ArrayRef },
...;
}
does
You can use does => "Role::Name" > as a shortcut for isa => ConsumerOf["Role::Name"].
Example: Using does
package Local::Marryable {
use Marlin::Role ...;
}
package Local::EiffelTower {
use Marlin
-with => [ "Local::Marryable" ],
...;
}
package Local::Person {
use Marlin::Util -all;
use Types::Common -all;
use Marlin
-with => [ "Local::Marryable" ],
children => { isa => ArrayRef },
spouse => {
is => rw,
does => "Local::Marryable",
clearer => true,
},
...;
}
my $alice = Local::Person->new;
my $eiffel = Local::EiffelTower->new;
...;
if ( $alice->spouse == $bob ) {
$alice->clear_spouse;
$bob->clear_spouse;
$alice->spouse( $eiffel );
}
coerce
Setting coerce => true enables type coercion for the attribute.
Example: Using coerce
package Person {
use Marlin
likes_cheese => { isa => 'Bool', coerce => true },
...;
}
my $alice = Person->new( ..., likes_cheese => 4 );
The value '4' in the above example isn't a valid boolean, but the Bool type constraint defines rules for coercing other values into booleans, and the value '4' becomes true.
For this to work, your type constraint needs to have coercions defined!
Example: Defining a Coercion Inline
package Person {
use Marlin::Util qw( true false );
use Types::Common -all;
use Marlin
"name!" => Str,
"nicknames" => {
isa => ArrayRef->plus_coercions(
Str, sub { split ":", $_ },
),
coerce => true,
},
...;
}
my $bob = Person->new(
name => "Robert",
nicknames => "Bob:Bobby:Robbie:Rob",
);
The value "Bob:Bobby:Robbie:Rob" isn't an ArrayRef so is coerced according to the rules for Str (strings).
The coerce option can alternatively be set to a coderef or an object with a coerce method.
Example: Defining a CodeRef Coercion
package Person {
use Marlin::Util qw( true false );
use Types::Common -all;
use Marlin
"name!" => Str,
"nicknames" => {
isa => ArrayRef,
coerce => sub { split ":", assert_Str($_) },
},
...;
}
my $bob = Person->new(
name => "Robert",
nicknames => "Bob:Bobby:Robbie:Rob",
);
Delegation
handles
If your attribute value is an object, delegation allows you to forward certain methods of your class to that object to be handled.
Example: Simple Delegation
package Person {
use Marlin
left_hand => {
isa => Object,
},
right_hand => {
isa => Object,
handles => { wave_hand => 'wave' },
},
...;
}
my $alice = Person->new(...);
# Equivalent to:
# $alice->right_hand->wave( speed => 4, time => '5 sec' );
$alice->wave_hand( speed => 4, time => '5 sec' );
It's possible to "curry" parameters. This means that some of the parameters which would be passed to the method are defined as part of declaring the delegation, so they don't need to be (and cannot be!) passed to the delegated method later.
Example: Currying
use v5.42.0;
package Person {
use Marlin
left_hand => {
isa => Object,
},
right_hand => {
isa => Object,
handles => {
wave_hand_quickly => [ 'wave', speed => 5 ],
wave_hand_normal => [ 'wave', speed => 3 ],
wave_hand_slowly => [ 'wave', speed => 1 ],
'my wave_hand' => 'wave', # lexical!
},
},
...;
sub wave_hand_unsurely_at_first( $self ) {
$self->&wave_hand( speed => 1, time => '3 sec' );
sleep( 1 );
$self->wave_hand_normal( time => '3 sec' );
}
}
my $alice = Person->new(...);
$alice->wave_hand_unsurely_at_first;
It is a really good idea to expose the functionality of your attributes this way. It's far better for someone using your Rocket object to be able to do:
$rocket->launch;
Instead of:
$rocket->engine->thruster->launch;
It means that they can launch your rocket without having to understand anything about its internal structure and which components do what. You might later replace your engine with an anti-gravity field and the $rocket->launch method you provide might remain unchanged from the perspective of outside code.
handles_via.
Marlin supports handles_via with Sub::HandlesVia. This allows you to delegate methods to values which are not objects but are Perl built-in types like hashrefs, arrayrefs, numbers, strings, etc.
use v5.42.0;
package Person {
use Types::Common -lexical, -types;
use Marlin
name => Str,
emails => {
is => 'ro',
isa => ArrayRef[Str]
default => sub { [] },
handles_via => 'Array',
handles => {
'add_email' => 'push',
'my find_emails' => 'grep', # lexical!
},
};
sub has_hotmail ( $self ) {
my @h = $self->&find_emails( sub { /\@hotmail\./ } );
return( @h > 0 );
}
}
my $bob = Person->new( name => 'Bob' );
$bob->add_email( 'bob@hotmail.example' );
die unless $bob->has_hotmail;
die if $bob->can('find_emails'); # will not die
Altering the Behaviour of Attributes
alias and alias_for
Allows you to establish aliases for an attribute.
Example: Aliases
use Marlin
name => {
required => true,
isa => Str,
alias => [ 'moniker', 'label' ],
}, ...;
Aliases are accepted in the constructor and also additional reader methods (or accessor methods for is => 'rw' attributes) are installed for each alias.
You can use alias_for => 'reader' or alias_for => 'accessor' to override which type of method is installed (though not on a per-alias basis). Technically it's possible to create writer/predicate/clearer aliases but that would be weird.
trigger
A method name or coderef to call after an attribute has been set.
If you use trigger => 1 or trigger => true, Marlin will assume a trigger name of "_trigger_" followed by your attribute name.
Marlin's triggers are a little more sophisticated than Moose's: within the trigger, you can call the setter again without worrying about re-triggering the trigger.
Example: Using Triggers
use v5.42.0;
package Person {
use Types::Common -types, -lexical;
use Marlin::Util -all, -lexical;
use Marlin
first_name => {
is => rw,
isa => Str,
trigger => sub ($me) { $me->clear_full_name },
},
last_name => {
is => rw,
isa => Str,
trigger => sub ($me) { $me->clear_full_name },
},
full_name => {
is => lazy,
isa => Str,
clearer => true,
builder => sub ($me) {
join q[ ], $me->first_name, $me->last_name;
},
};
}
my $person = Person->new(
first_name => 'Alice',
last_name => 'Smith',
);
say $person->full_name; # Alice Smith
$person->last_name( 'Jones' );
say $person->full_name; # Alice Jones
Currently if your class has any triggers, this will force any writers/accessors for the affected attributes to be implemented in Perl instead of XS. This is a good reason to have separate methods for readers and writers, so that the reader can remain fast!
It is usually possible to design your API in ways that don't require triggers.
Example: API Design to Avoid Triggers
use v5.42.0;
package Person {
use Types::Common -types, -lexical;
use Marlin::Util -all, -lexical;
use Marlin
first_name => {
is => ro,
isa => Str,
writer => 'my set_first_name',
},
last_name => {
is => ro,
isa => Str,
writer => 'my set_last_name',
},
full_name => {
is => lazy,
isa => Str,
clearer => 'my clear_full_name',
builder => sub ($me) {
join q[ ], $me->first_name, $me->last_name;
},
};
signature_for rename => (
method => true,
named => [
first_name => Optional[Str],
last_name => Optional[Str],
],
);
sub rename ( $self, $arg ) {
$self->&set_first_name( $arg->first_name )
if $arg->has_first_name;
$self->&set_last_name( $arg->last_name )
if $arg->has_last_name;
$self->&clear_full_name;
return $self;
}
}
my $person = Person->new(
first_name => 'Alice',
last_name => 'Smith',
);
say $person->full_name; # Alice Smith
$person->rename( last_name => 'Jones' );
say $person->full_name; # Alice Jones
auto_deref
Rarely used Moose option. If you call a reader or accessor in list context, will automatically apply @{} or %{} to the value if it's an arrayref or hashref.
Example: Using Auto-Deref
package Numbers {
use Marlin::Util -all;
use Marlin list => { is => ro, auto_deref => true };
}
my $primes = Numbers->new( list => [ 2, 3, 5, 7, 11 ] );
my $arrayref = $primes->list;
my ( $two, $three, $five, $seven, $eleven ) = $primes->list;
This option usually causes more issues than it solves. It is not recommended, but is supported because Moose supports it.
chain
By default, Marlin's writers, clearers, and (when used as writers) accessors are chainable. That means, they return the object itself. So this works:
Example: Using Chaining
my $result = $object->set_foo(1)->set_bar(2)->foobar;
$object->clear_foo->clear_bar;
However, you can set them to be not chainable using chain => false. Non-chainable clearers return the old value (like delete does). Non-chainable writers and accessors used as writers return the new value.
Chainable versions are usually slightly more useful, so that is the default since Marlin 0.022000.
storage
It is possible to give a hint to Marlin about how to store an attribute.
Example: The storage Option
use v5.12.0;
use Marlin::Util -all, -lexical;
use Types::Common -types, -lexical;
package Local::User {
use Marlin
'username!', => Str,
'password!' => {
is => bare,
isa => Str,
writer => 'change_password',
required => true,
storage => 'PRIVATE',
handles_via => 'String',
handles => { check_password => 'eq' },
};
}
my $bob = Local::User->new(
username => 'bd',
password => 'zi1ch',
);
die if exists $bob->{password}; # will not die
die if $bob->can('password'); # will not die
if ( $bob->check_password( 'zi1ch' ) ) {
...; # this code should execute
}
$bob->change_password( 'monk33' );
Note that in the above example, setting is => bare prevents any reader from being created, so you cannot call $bob->password to discover his password. This would normally suffer the issue that the password is still stored in $bob->{password} if you access the object as a hashref.
However, setting storage => "PRIVATE" tells Marlin to store the value privately so it no longer appears in the hashref, so won't be included in any Data::Dumper dumps sent to your logger, etc. This does complicate things if you ever need to serialize your object to a file or database though! (Note that while the value is not stored in the hashref, it is still stored somewhere. A determined Perl hacker can easily figure out where. This shouldn't be relied on in place of proper security.)
Marlin supports three storage methods for attributes: "HASH" (the default), "PRIVATE" (as above), and "NONE" (only used for constants).
Cloning Attribute Values
References provide shortcuts to data structures inside your object, allowing code outside your class to tamper with your object's internals in unpredictable ways.
Example: The Need for Cloning
my @array = ( 1, 2, 3 );
my $object = Local::Thing->new( numbers => \@array );
push @array, "Hello world";
Setting clone_on_write signals to the constructor and any writer/accessor methods that when they get passed a value, they should instead keep a clone of the value, breaking any references outside code might be keeping to it. So in the previous example, $object wouldn't have a reference to @array, but a reference to a clone of that array. Altering @array later wouldn't alter the copy that $object had.
Setting clone_on_read does the same thing for reader/accessor methods and avoids this altering your object:
Example: The Need for Cloning, Again
push @{ $object->numbers }, "Hello world";
Because $object->numbers would be returning a clone of the data the object holds internally instead of returning a direct reference to its internal data.
clone_on_write and clone_on_read can be set to true to enable deep cloning of values. If you need more fine-grained control of cloning, you can set them to a coderef or a method name.
Example: Fine-Grained Cloning Controls
package Local::Thing {
use Types::Common -types;
use Marlin
numbers => {
is => 'rw',
isa => ArrayRef[Int],
clone_on_write => sub ( $self, $attrname, $value ) {
...;
retun $cloned_value;
},
clone_on_read => '_clone',
handles_via => 'Array',
handles => { add_number => 'push' },
};
sub _clone ( $self, $attrname, $value ) {
...;
return $cloned_value;
}
}
The clone option is a shortcut for setting both clone_on_write and clone_on_read. You should usually use that as it's rare to need such fine-grained control.
Delegated methods (see handles and handles_via) operate on the internal copy of the data, bypassing the clone options. This means that in our example $object->add_number( 4 ) will correctly push a number onto the object's internal numbers arrayref instead of pushing it onto an ephemeral copy of the numbers arrayref.
It is worth noting that your internal use of the attributes will also trigger cloning. So for example, this will not work how you want it to.
Example: Cloning Gotcha
package Local::Thing {
use Types::Common -types;
use Marlin
numbers => {
is => 'rw',
isa => ArrayRef[Int],
clone => 1,
};
sub push_numbers ( $self, @more_numbers ) {
push @{ $self->numbers }, @more_numbers;
}
}
The clone_bypass option creates a second, internal accessor.
Example: The clone_bypass Option
package Local::Thing {
use Types::Common -types;
use Marlin
numbers => {
is => 'rw',
isa => ArrayRef[Int],
clone => 1,
clone_bypass => '_numbers_ref',
};
sub push_numbers ( $self, @more_numbers ) {
push @{ $self->_numbers_ref }, @more_numbers;
}
}
(Note that clone_bypass methods are always accessors, allowing you to get/set the attribute, even for read-only attributes! They are intended for your class's internal use only. Lexical clone bypass methods are supported and indeed recommended!)
Setting the cloning options makes most sense for attributes which you expect to be arrayrefs, hashrefs, or annoyingly mutable objects (like DateTime). It makes little sense for other attributes. It will slow down accessors and object construction.
This feature is inspired by MooseX::Extended::Manual::Cloning.
Extending Parent Attributes
You can use extends to indicate that this attribute extends or modifies an attribute inherited from a parent class or role.
Example: Extending Base Class Attributes
package Local::Person {
use Types::Common -types;
use Marlin
name => NonEmptyStr,
age => PositiveOrZeroNum;
}
package Local::Employee {
use Types::Common -types;
use Marlin::Util qw( true false );
use Marlin
-base => 'Local::Person',
# Require name for employees.
name => {
extends => true,
required => true,
},
# We only employ adults.
age => {
extends => true,
required => true,
isa => NumRange[ 18, undef ]
};
}
A shortcut for extends is a leading plus sign.
Example: Extending Base Class Attributes, Shorthand
package Local::Employee {
use Types::Common -types;
use Marlin -base => 'Local::Person',
'+name!', # Required
'+age!' => NumRange[ 18, undef ]; # Adults only
}
Marlin limits what changes child classes are allowed to make to the API they inherited from their parents. Some of the limitations:
Optional attributes can be made required, but required attributes cannot be made optional unless you also provide a default/builder.
Type constraints can be made more strict, but not looser. Type coercions can be enabled by child classes but not disabled if they're already enabled in the parent class.
Accessor-like methods (reader, writer, accessor, clearer, predicate) can be added, but accessors defined in parent classes cannot be replaced or removed.
Attribute storage type cannot be changed.
The auto_deref status cannot be changed.
In the rare case where an attribute has an option which you wish to delete, you can use $Marlin::Attribute::NONE.
Example: An Explicit NONE
package Local::ChildClass {
use Marlin::Attribute ();
use Marlin::Util -all;
use Marlin
-base => "Local::ParentClass",
# Parent class defined a default for this attribute
someattr => {
extends => true,
required => true,
default => $Marlin::Attribute::NONE,
};
}
SEE ALSO
Marlin::Manual::BetterMethods - next steps defining methods.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2026 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 405:
Unterminated C< ... > sequence
- Around line 1065:
=back without =over