#!/usr/bin/perl # $Id: ExportList.pm,v 1.5 2003/12/10 02:37:24 nothingmuch Exp $ package Object::Meta::Plugin::ExportList; # an object representing the skin of a plugin - what can be plugged and unseamed at the top level. use strict; use warnings; # this is a simple string based Object::Meta::Plugin::Export list. That is, all the methods are strings, and not code refs, # which gives a somewhat more controlled environment. # you could laxen these limits by writing your own ExportList, which will use code refs, and thus allow a plugin to nibble methods from other classes without base classing. # you'd also have to subclass Object::Meta::Plugin::Host to handle coderefs. Perhaps a dualvalue system could be useful. our $VERSION = 0.02; sub new { my $pkg = shift; my $plugin = shift; my $self = bless { plugin => $plugin, info => (ref $_[0] ? shift : Object::Meta::Plugin::ExportList::Info->new()), }, $pkg; my @methods = @_; if (@methods){ my %list = map { $_, undef } $plugin->exports(); # used to cross out what's not exported $self->{methods} = [ grep { exists $list{$_} } @methods ]; # filter the method list to be only what works; } else { $self->{methods} = [ $plugin->exports() ]; # everything unless otherwise stated } $self; } sub plugin { my $self = shift; $self->{plugin}; } sub exists { my $self = shift; $self->{index} = { map { $_, undef } @{ $self->{methods} } } unless (exists $self->{index}); if (wantarray){ # return a grepped list return grep { exists $self->{index}{$_} } @_; } else { # return a true or false return exists $self->{index}{$_[0]}; } } sub list { # list all under plugin my $self = shift; return @{ $self->{methods} }; } sub merge { # or another exoprt list into this one my $self = shift; my $x = shift; my %uniq; @{ $self->{methods} } = grep { not $uniq{$_}++ } @{ $self->{methods} }, $x->list(); $self; } sub unmerge { # and (not|complement) another export list into this one my $self = shift; my $x = shift; my %seen = map { $_, undef } $x->list(); @{ $self->{methods} } = grep { not exists $seen{$_} } @{ $self->{methods} }; } sub info { my $self = shift; $self->{info} = shift if (@_); $self->{info}; } package Object::Meta::Plugin::ExportList::Info; # for now it's basically a method->hashkey translator our $AUTOLOAD; sub new { my $pkg = shift; bless {@_ ? @_ : qw/ style implicit /}, $pkg; }; sub AUTOLOAD { my $self = shift; $AUTOLOAD =~ /.*::(.*)$/; my $method = $1; return if $method eq 'DESTROY'; $self->{$method} = shift if (@_); $self->{$method}; } 1; # Keep your mother happy. __END__ =pod =head1 NAME Object::Meta::Plugin::ExportList - An implementation of a very simple, string only export list, for use with Useful:: plugins. =head1 SYNOPSIS # the proper way my $plugin = GoodPlugin->new(); $host->plug($plugin); package GoodPlugin; # ... sub exports { qw/some methods/; } sub init { my $self = shift; return Object::Meta::Plugin::ExportList->new($self}; } # or if you prefer.... *drum roll* # the naughty way my $plugin = BadPlugin->new(); # doesn't need to be a plugin per se, since # it's not verified by plug(). All it needs # is to have a working can(). the export # list is responsible for the rest. # in short, this way init() needn't be defined. my $export = Object::Meta::Plugin::ExportList->new($plugin, qw/foo bar/); $host->register($export); =head1 DESCRIPTION An export list is an object a plugin hands over to a host, stating what it is going to give it. This is a very basic implementation, providing only the bare minimum methods needed to register a plugin. Unregistering one requires even less. =head1 METHODS =over 4 =item new PLUGIN [ INFO ] [ METHODS ... ] Creates a new export list object. If it is a reference, it will be assumed that the second argument is an info object. Provided that is the case, no info object will be created, and the argued one will be used in place. Any remaining arguments will be method names to be exported. If none are specified, the return value from the plugin's C method is used. =item list Returns a list of exported method names. =item plugin Returns the reference to the plugin object it represents. =item exists METHODS ... In scalar context will return truth if the first argument is a method that exists in the export list. In list context, it will return the method names given in @_, with the inexistent ones excluded. =item merge EXPORTLIST Performs an I with the methods of the argued export list. =item unmerge EXPORTLIST Performs an I of the I of the argued export list. =item info [ INFO ] Stores meta information regarding the plugin it represents. It's stored in the export list because the export list is what you use to communicate with the host. Currently only the I