package Venus::Role::Buildable; use 5.018; use strict; use warnings; use Venus::Role 'with'; # BUILDERS sub BUILD { my ($self, $args) = @_; if ($self->can('build_self')) { $self->build_self($args); } return $self; } sub BUILDARGS { my ($self, @args) = @_; # build_nil accepts a single-arg (empty hash) my $present = @args == 1 && ref $args[0] eq 'HASH' && !%{$args[0]}; # empty hash argument if ($self->can('build_nil') && $present) { @args = ($self->build_nil($args[0])); } # build_arg accepts a single-arg (non-hash) my $inflate = @args == 1 && ref $args[0] ne 'HASH'; # single argument if ($self->can('build_arg') && $inflate) { @args = ($self->build_arg($args[0])); } # build_args should not accept a single-arg (non-hash) my $ignore = @args == 1 && ref $args[0] ne 'HASH'; # standard arguments if ($self->can('build_args') && !$ignore) { @args = ($self->build_args(@args == 1 ? $args[0] : {@args})); } return (@args); } # EXPORTS sub EXPORT { ['BUILDARGS'] } 1; =head1 NAME Venus::Role::Buildable - Buildable Role =cut =head1 ABSTRACT Buildable Role for Perl 5 =cut =head1 SYNOPSIS package Example; use Venus::Class; with 'Venus::Role::Buildable'; attr 'test'; package main; my $example = Example->new; # $example->test; =cut =head1 DESCRIPTION This package modifies the consuming package and provides methods for hooking into object construction of the consuming class, e.g. handling single-arg object construction. =cut =head1 METHODS This package provides the following methods: =cut =head2 build_arg build_arg(Any $data) (HashRef) The build_arg method, if defined, is only called during object construction when a single non-hashref is provided. I> =over 4 =item build_arg example 1 package Example1; use Venus::Class; attr 'x'; attr 'y'; with 'Venus::Role::Buildable'; sub build_arg { my ($self, $data) = @_; $data = { x => $data, y => $data }; return $data; } package main; my $example = Example1->new(10); # $example->x; # $example->y; =back =cut =head2 build_args build_args(HashRef $data) (HashRef) The build_args method, if defined, is only called during object construction to hook into the handling of the arguments provided. I> =over 4 =item build_args example 1 package Example2; use Venus::Class; attr 'x'; attr 'y'; with 'Venus::Role::Buildable'; sub build_args { my ($self, $data) = @_; $data->{x} ||= int($data->{x} || 100); $data->{y} ||= int($data->{y} || 100); return $data; } package main; my $example = Example2->new(x => 10, y => 10); # $example->x; # $example->y; =back =cut =head2 build_nil build_nil(HashRef $data) (Any) The build_nil method, if defined, is only called during object construction when a single empty hashref is provided. I> =over 4 =item build_nil example 1 package Example4; use Venus::Class; attr 'x'; attr 'y'; with 'Venus::Role::Buildable'; sub build_nil { my ($self, $data) = @_; $data = { x => 10, y => 10 }; return $data; } package main; my $example = Example4->new({}); # $example->x; # $example->y; =back =cut =head2 build_self build_self(HashRef $data) (Self) The build_self method, if defined, is only called during object construction after all arguments have been handled and set. I> =over 4 =item build_self example 1 package Example3; use Venus::Class; attr 'x'; attr 'y'; with 'Venus::Role::Buildable'; sub build_self { my ($self, $data) = @_; die if !$self->x; die if !$self->y; return $self; } package main; my $example = Example3->new(x => 10, y => 10); # $example->x; # $example->y; =back =cut