How to get Moose to return an instance of a child class instead of its own class, for polymorphism

I want to create a generic class whose builder will not return an instance of this generic class, but an instance of a dedicated child class.

Since Moose does the auto-build of the object, I don’t understand if this is possible, and how to create a Moose class with Moose syntax and have this behavior.

$file = Repository->new(uri=>'sftp://blabla')e.g . : User asks: .... and returns the instance of `Repository :: _ Sftp``

The user will use $fileit as if it were an instance of a repository, without having to know the real subclass (polymorphism)

Note:
At the request, perhaps I should more clearly find out what I'm trying to achieve:
The goal of my class is to add new repository schemes (for example, via sftp), simply by creating a "hidden" class Repository :: _ Stfp and adding a case in the constructor The repository in the factory is the right specialized object depending on the URL. The repository will look like a virtual base class that provides an interface that would implement specialized objects.
All this consists in adding new repository schemes without the need to change the rest of the program: it will unconsciously deal with a specialized instance, as if it were an instance of a repository.

+5
2

new . , - .

:

  class RepositoryBuilder {
     has 'allow_network_repositories' => (
         is       => 'ro',
         isa      => 'Bool',
         required => 1,
     );

     method build_repository(Uri $url) {
        confess 'network access is not allowed'
            if $url->is_network_url && !$self->allow_network_repositories;

        my $class = $self->determine_class_for($url); # Repository::Whatever
        return $class->new( url => $url );
     }
  }

  role Repository { <whatever }

  class Repository::File with Repository {}
  class Repository::HTTP with Repository {}

. - , , , . "" . . ( , - . -, , , , . - .)

, , , , , . , Repository. ( API, , . - , ? , , , .)

. , , :

my $b = RepositoryBuilder->new( allow_network_repositories => 0 );
$b->build_repository( 'http://google.com/' ); # error
$b->build_repository( 'file:///home/whatever' ); # returns a Repository::Foo

:

my $b = RepositoryBuilder->new( allow_network_repositories => 1 );
$b->build_repository( 'http://google.com/' ); # Repository::HTTP

, , , , . , "" . , does isa:

class SomethingThatHasARepository {
    has 'repository' => (
       is       => 'ro',
       does     => 'Repository',
       required => 1,
    );
}

.

+6

( ). , Moose, CLASS->new, CLASS isa Moose:: Object CLASS.

, , , , ? , factory - , , :

package MyApp::Factory::Repository;

sub getFactory
{
     my ($class, %attrs);

     # figure out what the caller wants, and decide what type to return
     $class ||= 'Repository::_Sftp';
     return $class->new(attr1 => 'foo', attr2 => 'bar', %attrs);
}

my $file = MyApp::Factory::Repository->getFactory(uri=>'sftp://blabla');
+2

All Articles