NAME
Venus::Role::Optional - Optional Role
ABSTRACT
Optional Role for Perl 5
SYNOPSIS
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
DESCRIPTION
This package modifies the consuming package and provides methods for automating object construction and attribute accessors.
METHODS
This package provides the following methods:
clear
clear(string
$name
) (any)
The clear method deletes an attribute and returns the removed value.
Since 1.55
- clear example 2
-
# given: synopsis
package
main;
my
$lname
=
$person
->clear(
'lname'
);
# "Alderson"
my
$object
=
$person
;
# bless({fname => "Elliot"}, "Person")
has
has
(string
$name
) (boolean)
The has method returns truthy if the attribute specified exists, otherwise returns falsy.
Since 1.55
reset
reset
(string
$name
) (any)
The reset method rebuilds an attribute and returns the deleted value.
Since 1.55
- reset example 2
-
# given: synopsis
package
main;
my
$lname
=
$person
->
reset
(
'lname'
);
# "Alderson"
my
$object
=
$person
;
# bless({fname => "Elliot"}, "Person")
- reset example 3
-
# given: synopsis
package
main;
my
$lname
=
$person
->
reset
(
'lname'
,
'Smith'
);
# "Alderson"
my
$object
=
$person
;
# bless({fname => "Elliot", lname => "Smith"}, "Person")
FEATURES
This package provides the following features:
- asserting
-
This library provides a mechanism for automatically validating class attributes using Venus::Assert based on the return value of the attribute callback. The callback should be in the form of
assert_${name}
, and should return a Venus::Assert object or a "validation expression" (string) to be passed to the "expression" in Venus::Assert method.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
assert_fname {
return
'string'
;
}
sub
assert_lname {
return
'string'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
example 2
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
assert_fname {
return
'string'
;
}
sub
assert_lname {
return
'string'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=> 1234567890,
);
# Exception! (isa Venus::Check::Error)
example 3
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
assert_fname {
return
'string'
;
}
sub
assert_lname {
return
'string'
;
}
package
main;
my
$person
= Person->new(
fname
=> 1234567890,
lname
=>
'Alderson'
,
);
# Exception! (isa Venus::Check::Error)
example 4
package
Person;
use
Venus::Class;
attr
'progress'
;
sub
assert_progress {
return
'number | float'
;
}
package
main;
my
$person
= Person->new(
progress
=> 1,
);
# bless({progress => 1}, 'Person')
# my $person = Person->new(
# progress => 7.89,
# );
# bless({progress => 7.89}, 'Person')
# my $person = Person->new(
# progress => '1',
# );
# Exception! (isa Venus::Check::Error)
- building
-
This library provides a mechanism for automatically building class attributes on construction, and during getting and setting its value, after any default values are processed, based on the return value of the attribute callback. The callback should be in the form of
build_${name}
, and is passed any arguments provided.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
build_fname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
build_lname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
undef
;
}
package
main;
my
$person
= Person->new(
fname
=>
'elliot'
,
lname
=>
'alderson'
,
email
=>
'E.ALDERSON@E-CORP.org'
,
);
# bless({fname => 'Elliot', lname => 'Alderson', ...}, 'Person')
# $person->fname;
# "Elliot"
# $person->lname;
# "Alderson"
# $person->email;
# "e.alderson@e-corp.org"
example 2
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
build_fname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
build_lname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
undef
;
}
package
Person;
sub
build_email {
my
(
$self
,
$value
) =
@_
;
return
lc
join
'@'
, (
join
'.'
,
substr
(
$self
->fname, 0, 1),
$self
->lname),
'e-corp.org'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# $person->email;
# "e.alderson@e-corp.org"
example 3
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
sub
build_fname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
coerce_fname {
return
'Venus::String'
;
}
sub
build_lname {
my
(
$self
,
$value
) =
@_
;
return
$value
?
ucfirst
$value
:
undef
;
}
sub
coerce_lname {
return
'Venus::String'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'elliot'
,
lname
=>
'alderson'
,
);
# bless({
# fname => bless({value => 'Elliot'}, 'Venus::String'),
# lname => bless({value => 'Alderson'}, 'Venus::String')
# }, 'Person')
example 4
package
Person;
use
Venus::Class;
attr
'email'
;
sub
build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
undef
;
}
sub
coerce_email {
return
'Venus::String'
;
}
package
main;
my
$person
= Person->new(
email
=>
'Elliot.Alderson@e-corp.org'
,
);
# bless({
# email => bless({value => 'elliot.alderson@e-corp.org'}, 'Venus::String'),
# }, 'Person')
example 5
package
Person;
use
Venus::Class;
attr
'email'
;
sub
build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
undef
;
}
sub
default_email {
return
'NO-REPLY@E-CORP.ORG'
;
}
package
main;
my
$person
= Person->new;
# bless({email => 'no-reply@e-corp.org'}, 'Person')
- checking
-
This library provides a mechanism for automatically checking class attributes after getting or setting its value. The callback should be in the form of
check_${name}
, and is passed any arguments provided.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
check_fname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
return
true
if
lc
(
$value
) eq
'elliot'
;
}
return
false;
}
sub
check_lname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
return
true
if
lc
(
$value
) eq
'alderson'
;
}
return
false;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
example 2
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
check_fname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
return
true
if
lc
(
$value
) eq
'elliot'
;
}
return
false;
}
sub
check_lname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
return
true
if
lc
(
$value
) eq
'alderson'
;
}
return
false;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# $person->lname('Alderson');
# "Alderson"
# $person->lname('');
# Exception! (isa Person::Error)
- coercing
-
This library provides a mechanism for automatically coercing class attributes into class instances using Venus::Space based on the return value of the attribute callback. The callback should be in the form of
coerce_${name}
, and should return the name of the package to be constructed. That package will be instantiated via the customarynew
method, passing the data recevied as its arguments.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
coerce_fname {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
sub
coerce_lname {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
sub
coerce_email {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({
# 'fname' => bless({'value' => 'Elliot'}, 'Venus::String'),
# 'lname' => bless({'value' => 'Alderson'}, 'Venus::String')
# }, 'Person')
example 2
package
Person;
use
Venus::Class;
use
Venus::String;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
coerce_fname {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
sub
coerce_lname {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
sub
coerce_email {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
package
main;
my
$person
= Person->new(
email
=>
'e.alderson@e-corp.org'
,
);
# bless({
# 'email' => bless({'value' => 'e.alderson@e-corp.org'}, 'Venus::String'),
# }, 'Person')
example 3
package
Person;
use
Venus::Class;
attr
'email'
;
sub
coerce_email {
my
(
$self
,
$value
) =
@_
;
return
'Venus::String'
;
}
sub
default_email {
my
(
$self
,
$value
) =
@_
;
return
'no-reply@e-corp.org'
;
}
package
main;
my
$person
= Person->new;
# bless({
# 'email' => bless({'value' => 'no-reply@e-corp.org'}, 'Venus::String'),
# }, 'Person')
- defaulting
-
This library provides a mechanism for automatically defaulting class attributes to predefined values, statically or dynamically based on the return value of the attribute callback. The callback should be in the form of
default_${name}
, and should return the value to be used if no value exists or has been provided to the constructor.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
default_lname {
my
(
$self
,
$value
) =
@_
;
return
'Alderson'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# $person->lname('Johnston');
# "Johnston"
# $person->reset('lname');
# "Johnston"
# $person->lname;
# "Alderson"
- initialing
-
This library provides a mechanism for automatically setting class attributes to predefined values, statically or dynamically based on the return value of the attribute callback. The callback should be in the form of
initial_${name}
, and should return the value to be used if no value has been provided to the constructor. This behavior is similar to the "defaulting" mechanism but is only executed during object construction.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
initial_lname {
my
(
$self
,
$value
) =
@_
;
return
'Alderson'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# $person->lname('Johnston');
# "Johnston"
# $person->reset('lname');
# "Johnston"
# $person->lname;
# undef
- lazy-building
-
This library provides a mechanism for automatically building class attributes during getting and setting its value, after any default values are processed, based on the return value of the attribute callback. The callback should be in the form of
lazy_build_${name}
, and is passed any arguments provided.example 1
package
Person;
use
Venus::Class;
attr
'email'
;
sub
lazy_build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
'no-reply@e-corp.org'
;
}
package
main;
my
$person
= Person->new;
# bless({}, 'Person')
# $person->email;
# "no-reply@e-corp.org"
example 2
package
Person;
use
Venus::Class;
attr
'email'
;
sub
coerce_email {
return
'Venus::String'
;
}
sub
lazy_build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
'no-reply@e-corp.org'
;
}
package
main;
my
$person
= Person->new;
# bless({}, 'Person')
# $person->email;
# bless({value => 'no-reply@e-corp.org'}, 'Venus::String')
example 3
package
Person;
use
Venus::Class;
attr
'email'
;
sub
default_email {
return
'NO-REPLY@E-CORP.ORG'
;
}
sub
lazy_build_email {
my
(
$self
,
$value
) =
@_
;
return
$value
?
lc
$value
:
undef
;
}
package
main;
my
$person
= Person->new;
# bless({}, 'Person')
# $person->email;
# "no-reply@e-corp.org"
- reading
-
This library provides a mechanism for hooking into the class attribute reader (accessor) for reading values via the the attribute reader callback. The callback should be in the form of
read_${name}
, and should read and return the value for the attribute specified.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
read_fname {
my
(
$self
,
$value
) =
@_
;
return
ucfirst
$self
->{fname};
}
sub
read_lname {
my
(
$self
,
$value
) =
@_
;
return
ucfirst
$self
->{lname};
}
package
main;
my
$person
= Person->new(
fname
=>
'elliot'
,
lname
=>
'alderson'
,
);
# bless({fname => 'elliot', lname => 'alderson'}, 'Person')
# $person->fname;
# "Elliot"
# $person->lname;
# "Alderson"
- readonly
-
This library provides a mechanism for marking class attributes as "readonly" (or not) based on the return value of the attribute callback. The callback should be in the form of
readonly_${name}
, and should return truthy to automatically throw an exception if a change is attempted.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
readonly_fname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
readonly_lname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
$person
->fname(
'Mister'
);
# Exception! (isa Person::Error)
# $person->lname('Johnston');
# Exception! (isa Person::Error)
- readwrite
-
This library provides a mechanism for marking class attributes as "readwrite" (or not) based on the return value of the attribute callback. The callback should be in the form of
readwrite_${name}
, and should return falsy to automatically throw an exception if a change is attempted.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
readwrite_fname {
my
(
$self
,
$value
) =
@_
;
return
false;
}
sub
readwrite_lname {
my
(
$self
,
$value
) =
@_
;
return
false;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
$person
->fname(
'Mister'
);
# Exception! (isa Person::Error)
# $person->lname('Johnston');
# Exception! (isa Person::Error)
- requiring
-
This library provides a mechanism for marking class attributes as "required" (i.e. to be provided to the constructor) based on the return value of the attribute callback. The callback should be in the form of
require_${name}
, and should return truthy to automatically throw an exception if the related attribute is missing.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
require_fname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_lname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_email {
my
(
$self
,
$value
) =
@_
;
return
false;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
example 2
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
require_fname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_lname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_email {
my
(
$self
,
$value
) =
@_
;
return
false;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
);
# Exception! (isa Person::Error)
example 3
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
require_fname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_lname {
my
(
$self
,
$value
) =
@_
;
return
true;
}
sub
require_email {
my
(
$self
,
$value
) =
@_
;
return
false;
}
package
main;
my
$person
= Person->new(
lname
=>
'Alderson'
,
);
# Exception! (isa Person::Error)
- self-asserting
-
This library provides a mechanism for automatically validating class attributes using the attribute callback provided. The author is resposible for validating the state of the attribute and raising an exception when an attribute fails validation. The callback should be in the form of
self_assert_${name}
.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
sub
self_assert_fname {
my
(
$self
,
$value
) =
@_
;
die
'Bad fname'
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
sub
self_assert_lname {
my
(
$self
,
$value
) =
@_
;
die
'Bad lname'
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# my $person = Person->new(fname => '@ElliotAlderson');
# Exception! (isa Venus::Error)
example 2
package
Person;
attr
'fname'
;
attr
'lname'
;
sub
self_assert_fname {
my
(
$self
,
$value
) =
@_
;
raise
'Person::Error::BadFname'
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
sub
self_assert_lname {
my
(
$self
,
$value
) =
@_
;
raise
'Person::Error::BadLname'
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# my $person = Person->new(lname => '@AldersonElliot');
# Exception! (isa Person::Error::BadLname, isa Venus::Error)
example 3
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
sub
self_assert_fname {
my
(
$self
,
$value
) =
@_
;
die
$self
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
sub
self_assert_lname {
my
(
$self
,
$value
) =
@_
;
die
$self
if
$value
&&
$value
!~
'^[a-zA-Z]'
;
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({fname => 'Elliot', lname => 'Alderson'}, 'Person')
# my $person = Person->new(fname => rand);
# Exception! (isa Person)
- self-coercing
-
This library provides a mechanism for automatically coercing class attributes using the attribute callback provided. The author is resposible for any transformations to the attribute and value. The callback should be in the form of
self_coerce_${name}
.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
sub
self_coerce_fname {
my
(
$self
,
$value
) =
@_
;
return
Venus::String->new(
$value
||
''
);
}
sub
self_coerce_lname {
my
(
$self
,
$value
) =
@_
;
return
Venus::String->new(
$value
||
''
);
}
package
main;
my
$person
= Person->new(
fname
=>
'Elliot'
,
lname
=>
'Alderson'
,
);
# bless({
# fname => bless({value => 'Elliot'}, 'Venus::String'),
# lname => bless({value => 'Alderson'}, 'Venus::String')
# }, 'Person')
example 2
package
Person;
use
Venus::Class;
attr
'email'
;
sub
default_email {
my
(
$self
,
$value
) =
@_
;
return
'no-reply@e-corp.org'
;
}
sub
self_coerce_email {
my
(
$self
,
$value
) =
@_
;
return
Venus::String->new(
$value
||
''
);
}
package
main;
my
$person
= Person->new;
# bless({
# 'email' => bless({'value' => 'no-reply@e-corp.org'}, 'Venus::String'),
# }, 'Person')
- triggering
-
This library provides a mechanism for automatically triggering routines after reading or writing class attributes via an attribute callback. The callback should be in the form of
trigger_${name}
, and will be invoked after the related attribute is read or written.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
trigger_fname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
$self
->{dirty}{fname} =
$value
;
}
return
;
}
sub
trigger_lname {
my
(
$self
,
$value
) =
@_
;
if
(
$value
) {
$self
->{dirty}{lname} =
$value
;
}
return
;
}
package
main;
my
$person
= Person->new;
# bless({}, 'Person')
# $person->fname('Elliot');
# "Elliot"
# $person->lname('Alderson');
# "Alderson"
# my $object = $person;
# bless({..., dirty => {fname => 'Elliot', lname => 'Alderson'}}, 'Person')
- writing
-
This library provides a mechanism for hooking into the class attribute writer (accessor) for writing values via the the attribute writer callback. The callback should be in the form of
write_${name}
, and should set and return the value for the attribute specified.example 1
package
Person;
use
Venus::Class;
attr
'fname'
;
attr
'lname'
;
attr
'email'
;
sub
write_fname {
my
(
$self
,
$value
) =
@_
;
return
$self
->{fname} =
ucfirst
$value
;
}
sub
write_lname {
my
(
$self
,
$value
) =
@_
;
return
$self
->{lname} =
ucfirst
$value
;
}
package
main;
my
$person
= Person->new;
# bless({}, 'Person')
# $person->fname('elliot');
# "Elliot"
# $person->lname('alderson');
# "Alderson"
AUTHORS
Awncorp, awncorp@cpan.org
LICENSE
Copyright (C) 2022, Awncorp, awncorp@cpan.org
.
This program is free software, you can redistribute it and/or modify it under the terms of the Apache license version 2.0.