nysus has asked for the wisdom of the Perl Monks concerning the following question:

I have a Moose class which represents websites on a server, call it the Website class. This is a parent class of two subclasses: Website::Drupal and Website::WordPress. Website objects start out as a generic. Once the object "learns" which type of object it is, I'd like it to subclass itself as Website::WordPress or Website::Drupal. I believe that "coercion" is what I need to do. I read this but I couldn't really make heads or tails of it and so I'm not sure if I'm on the right track. If someone could give me some hints to steer me in the right direction, I'd appreciate it.

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Converting Moose object to a subclass of itself
by choroba (Cardinal) on Feb 27, 2017 at 03:29 UTC
    Returning objects of different types based on arguments... this sounds like the Factory design pattern.

    Update: An example added. It doesn't make much sense, as I'm not sure what your classes do and how they differ. Instead of having the same ancestor (Website), they could share a role instead.

    #!/usr/bin/perl use warnings; use strict; { package Website::Factory; use Moose; sub build { my ($self, %args) = @_; my $type = delete $args{type}; my $class; die "Unknown type '$type'.\n" unless $class = { 'drupal' => 'Website::Drupal', 'wordpress' => 'Website::WordPress', }->{$type}; return $class->new(%args) } } { package Website; use Moose; has path => ( is => 'ro', isa => 'Str' ); } { package Website::Drupal; use Moose; extends 'Website'; } { package Website::WordPress; use Moose; extends 'Website'; } my $wf = 'Website::Factory'->new; my $drupal = $wf->build( type => 'drupal', path => '/index.php' ); use Data::Dumper; print Dumper($drupal);

    Advantages: you can now add a new type easily. You can (to some extent) change the implementation of the Website classes without need to change the code that creates their instances.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      In this case choroba, I think an example is warranted for this thread.

      Interesting idea to create a factory object. I will play with this. I just posted up a more thorough review of my code here: http://perlmonks.org/?node_id=1182955. You'll see I stuff my "factory" inside of a method. Maybe that's a weird thing to do.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

Re: Converting Moose object to a subclass of itself
by kcott (Archbishop) on Feb 27, 2017 at 00:41 UTC

    G'day nysus,

    It seems to me that what you want here is Moose::Role.

    "Once the object "learns" which type of object it is, ..."

    Would "learns which role it's going to take on" be a reasonable paraphrase?

    Take a look at the apply_all_roles() function in Moose::Util.

    — Ken

Re: Converting Moose object to a subclass of itself
by nysus (Parson) on Feb 26, 2017 at 21:00 UTC

      Can you explain why you're wanting to do this? Why not just use the instance of the child object directly, and leave the parent as-is, as a parent class object? Or if you want to use the child object through the parent, stuff a copy of the object into the parent and use it from there?

      It seems as though re-blessing the object may lead to potential confusion down the road, and may break things if someone tries to generate another object from the parent, instead of using the class:

      # this may break/do something unexpected if $self is # re-blessed my $obj = $self->new(%params); # worse, the wordpress child probably doesn't have a wordpress_new() # method, as it has no need to. The parent probably calls new() on the # child through a wordpress-type instantiator my $obj = $self->wordpress_new();

      Confusion?

      my $parent = Foo::Bar->new; # after rebless, calling a documented method in the parent # class may cause major confusion (or worse, subtle breakage far away) # if the child has the same method overridden, and does something # totally different $parent->documented_method(); # got foo and not bar!?

        I'll do my best to explain. Basically, my thought is that the methods for each subclass will be different. For example, the method to obtain the database password for a Drupal site is different than the method for obtaining a WordPress database password. Each CMS has a differently named config file and a different way of storing the password in the config file. So, it seems to me, that it would be good to set up two subclasses, one for Drupal and one for WordPress, that have methods specialized for obtaining the database password and other settings.

        $PM = "Perl Monk's";
        $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate";
        $nysus = $PM . ' ' . $MCF;
        Click here if you love Perl Monks

        "Can you explain why you're wanting to do this?"

        OP is clueless.