NAME
    Zydeco - Jazz up your Perl

SYNOPSIS
    MyApp.pm

      use v5.14;
      use strict;
      use warnings;
  
      package MyApp {
        use Zydeco;
    
        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

      use v5.14;
      use strict;
      use warnings;
      use MyApp;
      use MyApp::Types qw( is_Person );
  
      # Create a new MyApp::Person object.
      #
      my $alice  = MyApp->new_woman("Alice");
      is_Person($alice) or die;
  
      # The string "Bob" will be coerced to a MyApp::Person.
      #
      $alice->greet(friend => "Bob", greeting => 'Hi');

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);
      }

  `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
        ...;
      }

  `multi method`
      multi method myfunc {
        ...;
      }
  
      multi method myfunc ( Int $x, ArrayRef $y ) {
        ...;
      }
  
      multi method myfunc ( HashRef *collection, Int *index ) {
        ...;
      }

  `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;
      }

  `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`
      package MyApp {
        use Zydeco;
        include Roles;
        include Classes;
      }
  
      # MyApp/Roles.zydeco.pm
      role Foo;
      role Bar;
  
      # MyApp/Classes.zydeco.pm
      class Foo::Bar with Foo, Bar;

  `Zydeco::PACKAGE_SPEC()`
      package MyApp {
        use Zydeco;
    
        class MyClass {
          has name;
          Zydeco::PACKAGE_SPEC()->{has}{name}{required} = true;
        }
      }

IMPORTS
    Booleans:

    `true`
    `false`

    Attribute privacy:

    `rw`
    `rwp`
    `ro`
    `lazy`
    `bare`
    `private`

    Utilities:

    `blessed($var)`
    `confess($format, @args)`

    Types:

      use Types::Standard         qw( -types -is -assert );
      use Types::Common::Numeric  qw( -types -is -assert );
      use Types::Common::String   qw( -types -is -assert );

    Pragmas:

      use strict;
      use warnings;
  
      # Perl 5.14 and Perl 5.16
      use feature qw( say state unicode_strings );
  
      # Perl 5.18 or above
      use feature qw( say state unicode_strings
                      unicode_eval evalbytes current_sub fc );

    Zydeco also imports Syntax::Keyword::Try.

  Selective Import
    You can choose which parts of Zydeco you import:

      package MyApp {
        use Zydeco keywords => [qw/
          -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 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.

