NAME
Zydeco - Jazz up your Perl
SYNOPSIS
MyApp.pm
use
v5.14;
use
strict;
use
warnings;
package
MyApp {
class Person {
has
name (
type
=> Str,
required
=> true );
has
gender (
type
=> Str );
factory new_man (Str
$name
) {
return
$class
->new(
name
=>
$name
,
gender
=>
'male'
);
}
factory new_woman (Str
$name
) {
return
$class
->new(
name
=>
$name
,
gender
=>
'female'
);
}
method greet (Person
*friend
, Str
*greeting
=
"Hello"
) {
printf
(
"%s, %s!\n"
,
$arg
->greeting,
$arg
->friend->name);
}
coerce from Str via from_string {
return
$class
->new(
name
=>
$_
);
}
}
}
my_script.pl
DESCRIPTION
Zydeco is a Perl module to jazz up your object-oriented programming. It fuses together:
Classes, roles, and interfaces
Powerful and concise attribute definitions
Methods with signatures, type constraints, and coercion
Factories to help your objects make other objects
Multimethods
Method modifiers to easily wrap or override inherited methods
Powerful delegation features
True private methods and attributes
Parameterizable classes and roles
Syntactic sugar as sweet as pecan pie
Zydeco::Manual is probably the best place to start.
If Zydeco is too slow or has too many dependencies for you, check out Zydeco::Lite.
KEYWORDS
class
class MyClass;
class MyClass { ... }
class BaseClass {
class SubClass;
}
class MyGenerator (
@args
) { ... }
my
$class
= MyApp->generate_mygenerator(...);
my
$class
=
do
{ class; };
my
$class
=
do
{ class { ... } };
my
$generator
=
do
{ class (
@args
) { ... } };
my
$class
=
$generator
->generate_package(...);
abstract class
abstract class MyClass;
abstract class MyClass { ... }
abstract class BaseClass {
class SubClass;
}
my
$class
=
do
{ abstract class; };
my
$class
=
do
{ abstract class { ... } };
role
role MyRole;
role MyRole { ... }
role MyGenerator (
@args
) { ... }
my
$role
= MyApp->generate_mygenerator(...);
my
$role
=
do
{ role; };
my
$role
=
do
{ role { ... } };
my
$generator
=
do
{ role (
@args
) { ... } };
my
$role
=
$generator
->generate_package(...);
interface
interface MyIface;
interface MyIface { ... }
interface MyGenerator (
@args
) { ... }
my
$interface
= MyApp->generate_mygenerator(...);
my
$iface
=
do
{ interface; };
my
$iface
=
do
{ interface { ... } };
my
$generator
=
do
{ interface (
@args
) { ... } };
my
$iface
=
$generator
->generate_package(...);
toolkit
class MyClass {
toolkit Moose;
}
class MyClass {
toolkit Mouse;
}
class MyClass {
toolkit Moo;
}
class MyClass {
toolkit Moose (StrictConstructor);
}
Modules in parentheses are prefixed by "$toolkit\::X"
unless they start with "::" and loaded. Not all modules are useful to load this way because they are loaded too late to have a lexical effect, and because code inside the class will not be able to see functions exported into the class.
extends
class MyClass
extends
BaseClass;
class MyClass
extends
BaseClass, OtherClass;
class MyClass {
extends
BaseClass;
}
class MyClass {
extends
BaseClass, OtherClass;
}
with
class MyClass
with
SomeRole;
class MyClass
with
SomeRole, OtherRole;
class MyClass
extends
BaseClass
with
SomeRole, OtherRole;
class MyClass {
with
SomeRole;
}
class MyClass {
with
SomeRole, OtherRole;
}
class MyClass {
with
RoleGenerator(
@args
), OtherRole;
}
class MyClass {
with
TagRole?, OtherTagRole?;
}
role MyRole {
with
OtherRole;
}
role MyRole
with
OtherRole {
...;
}
role MyRole
with
SomeRole, OtherRole;
begin
class MyClass {
begin {
say
"defining $kind $package"
; }
}
role MyRole {
begin {
say
"defining $kind $package"
; }
}
end
class MyClass {
end {
say
"finished defining $kind $package"
; }
}
role MyRole {
end {
say
"finished defining $kind $package"
; }
}
before_apply
role MyRole {
before_apply {
say
"applying $role to $package"
; }
}
after_apply
role MyRole {
after_apply {
say
"finished applying $role to $package"
; }
}
has
class MyClass {
has
foo;
}
class MyClass {
has
foo;
class MySubClass {
has
+foo;
}
}
class MyClass {
has
foo, bar;
}
class MyClass {
has
foo!, bar;
}
class MyClass {
has
{
"fo"
.
"o"
};
}
class MyClass {
has
$foo
;
# private attribute withg lexical accessor
}
class MyClass {
has
foo (
is
=> ro,
type
=> Int,
default
=> 1 ) ;
}
class MyClass {
has
name =
"Anonymous"
;
has
uc_name =
uc
(
$self
->name);
}
param
Synonym for has
but defaults to required => true
.
class MyClass {
param foo (
type
=> Str );
}
field
Synonym for has
but defaults to init_arg => undef
.
class MyClass {
field foo (
builder
=> true );
method _build_foo { ... }
}
constant
class MyClass {
constant PI = 3.2;
}
interface Serializable {
requires serialize;
constant PRETTY = 1;
constant UTF8 = 2;
constant CANONICAL = 4;
}
method
method myfunc {
...;
}
method myfunc ( Int
$x
, ArrayRef
$y
) {
...;
}
method myfunc ( HashRef
*collection
, Int
*index
) {
...;
}
method myfunc :optimize ( Int
$x
, ArrayRef
$y
) {
...;
}
my
$myfunc
=
do
{ method () {
...;
}};
method
$myfunc
() {
# lexical method
...;
}
symmethod
symmethod myfunc {
...;
}
symmethod myfunc ( Int
$x
, ArrayRef
$y
) {
...;
}
multi method
multi method myfunc {
...;
}
multi method myfunc ( Int
$x
, ArrayRef
$y
) {
...;
}
multi method myfunc ( HashRef
*collection
, Int
*index
) {
...;
}
# lexical multimethod - make sure you declare the variable first
#
my
$otherfunc
;
multi method
$otherfunc
( CodeRef
$x
) { ... }
multi method
$otherfunc
( HashRef
$x
) { ... }
requires
role MyRole {
requires serialize;
requires deserialize (Str
$input
);
}
before
before
myfunc {
...;
}
before
myfunc ( Int
$x
, ArrayRef
$y
) {
...;
}
after
after
myfunc {
...;
}
after
myfunc ( Int
$x
, ArrayRef
$y
) {
...;
}
around
around
myfunc {
...;
my
$return
=
$self
->
$next
(
@_
[2..
$#_
] );
...;
return
$return
;
}
around
myfunc ( Int
$x
, ArrayRef
$y
) {
...;
my
$return
=
$self
->
$next
(
@_
);
...;
return
$return
;
}
factory
class MyThing {
factory new_thing {
...;
}
}
class MyThing {
factory new_thing ( Int
$x
, ArrayRef
$y
) {
...;
}
}
class MyThing {
factory new_thing ( HashRef
*collection
, Int
*index
) {
...;
}
}
class MyThing {
method _make_thing {
...;
}
factory new_thing via _make_thing;
}
class MyThing {
factory new_thing;
}
multi factory
class MyThing {
multi factory new_thing ( ArrayRef
$x
) {
...;
}
multi factory new_thing ( HashRef
$x
) {
...;
}
}
type_name
class Person {
type_name Hooman;
}
role Serializer {
type_name Ser;
}
coerce
class Widget {
has
id (
type
=> Int);
coerce from Int via from_id {
$class
->new(
id
=>
$_
);
}
}
class Widget {
has
id (
type
=> Int);
coerce from Int via from_id;
method from_id (
$id
) {
$class
->new(
id
=>
$id
);
}
}
overload
class Person {
has
name (
type
=> Str);
overload(
q[""]
=>
'name'
,
fallback
=> true);
}
version
class MyClass 1.0;
class MyClass {
version
'1.0'
;
}
authority
class MyClass {
authority
'cpan:TOBYINK'
;
}
include
Zydeco::PACKAGE_SPEC()
IMPORTS
Booleans:
Attribute privacy:
Utilities:
Types:
Pragmas:
Zydeco also imports Syntax::Keyword::Try.
Selective Import
You can choose which parts of Zydeco you import:
package
MyApp {
-booleans
-privacy
-utils
-types
-is
-assert
-features
try
class abstract role interface
begin end before_apply after_apply
include toolkit extends with requires
has constant method multi factory before after around
type_name coerce
version authority overload
/
];
Unimport
no Zydeco
will clear up:
class abstract role interface
include toolkit begin end
extends
with
requires
has
constant method multi factory
before
after
around
type_name coerce
version authority overload
But won't clear up things Zydeco imported for you from other packages. Use no MooX::Press::Keywords
, no Types::Standard
, etc to do that, or just use namespace::autoclean.
BUGS
Please report any bugs to http://rt.cpan.org/Dist/Display.html?Queue=Zydeco.
TODO
Plugin system
Zydeco can often load MooX/MouseX/MooseX plugins and work fine with them, but some things won't work, like plugins that rely on being able to wrap has
. So it would be nice to have a plugin system that extensions can hook into.
If you're interested in extending Zydeco, file a bug report about it and let's have a conversation about the best way for that to happen. I probably won't start a plugin API until someone actually wants to write a plugin, because that will give me a better idea about what kind of API is required.
SEE ALSO
Zydeco manual: Zydeco::Manual.
Zydeco website: http://zydeco.toby.ink/.
Less magic versions: Zydeco::Lite, MooX::Press. (Zydeco is just a wrapper around MooX::Press, providing a nicer syntax. Zydeco::Lite is an alternative wrapper, using less magic.)
Important underlying technologies: Moo, Type::Tiny::Manual, Sub::HandlesVia, Sub::MultiMethod, Lexical::Accessor, Syntax::Keyword::Try, Role::Hooks.
Similar modules: Moops, Kavorka, Dios, MooseX::Declare.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2020-2022 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.