Ivan Petrenko
Ivan Petrenko

Reputation: 21

Perl: How to emulate Ruby's "include/extend" mechanism?

How I can emulate in my Perl code things like Ruby's "include"/"extend" mechanism?

Let's take for example the following code in Ruby:

module ActiveRecord
  class Base

    class << self
      #...
    end

    #...
  end

  Base.class_eval do
    include ActiveRecord::Persistence
    extend ActiveModel::Naming
    extend QueryCache::ClassMethods
    extend ActiveSupport::Benchmarkable
    extend ActiveSupport::DescendantsTracker

    include ActiveModel::Conversion
    include Validations
    extend CounterCache
    include Locking::Optimistic, Locking::Pessimistic
    include AttributeMethods
    ...
  end
end

It leads me to ask this question, because I can't find any clear idea during several days of researching. So, maybe there exists some good way to organize it in Perl?

Upvotes: 2

Views: 299

Answers (3)

draegtun
draegtun

Reputation: 22560

A literal translation of this code to Perl/Moose would (kinda) look like this:

package ActiveRecord::Base;
use Moose;
use namespace::autoclean;

with qw(
    ActiveRecord::Persistence
    ActiveModel::Naming
    QueryCache::ClassMethods
    ActiveSupport::Benchmarkable
    ActiveSupport::DescendantsTracker
    ActiveModel::Conversion
    Validations
    CounterCache
    Locking::Optimistic
    Locking::Pessimistic
    AttributeMethods
);

__PACKAGE__->meta->make_immutable;
1;

Above uses Moose Roles which are equivalent to Ruby's mixins.

In Ruby include is for mixing in instance methods whereas extend is for class mixins. In Perl all methods can be called by class or instance so roles are added using with.

Upvotes: 1

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

Here is a small example:

#!/usr/bin/env perl

use 5.014;

package My::Quoted {
    use Role::Tiny;
    sub quoted_name {
        my $self = shift;
        return sprintf q{"%s"}, $self->name;
    }
}

package My::One {
    use Moo;
    has name => (is => 'ro');

    sub greet {
        my $self = shift;
        return sprintf 'Hello %s', $self->name;
    }
}

package My::Two {
    use Moo;

    extends 'My::One';
    with 'My::Quoted';

    sub greet {
        my $self = shift;
        return sprintf 'Merhaba %s', $self->quoted_name;
    }
}

package main {
    run('Perl');
    sub run {
        my $name = shift;

        my $x = My::Two->new({name => $name});
        my $y = My::One->new({name => $name});

        say $_->greet for $x, $y;
    }
}

Output:

Merhaba "Perl"
Hello Perl

Upvotes: 3

David-SkyMesh
David-SkyMesh

Reputation: 5171

That looks like traits/mixins vs inheritance, both done at runtime.

The traits/mixins parts are covered by a Perl6 concept called a Role.

How to implement in Perl 5? Look no further than Moose (see also the perldoc for Moose)

I believe it started as a proving ground for the OO/meta language support features headed for Perl 6, but in Perl 5. Now it has taken on a life of its own and a great many CPAN packages have dependencies on Moose.

Moose implements a wide variety of Object Oriented language constructs (from a few different OO paradigms) and is very extensible.

An explanation of the concepts in Moose and how they map to constructs in other languages can be found in the Concepts section of the Moose manual

Additionally, the Moose and MooseX namespaces on CPAN are chock full of complimentary (or experimental) packages to add support for even more OO constructs.

Upvotes: 7

Related Questions