Tags:
create new tag
, view all tags
At the moment contrib packages are in trouble if they need to initialise. There needs to be an initialiser, e.g.
package TWiki::Contrib::SexySkin;

use vars qw($VERSION $RELEASE);

$VERSION = '$Rev$';
$RELEASE = 'TWiki-4';

BEGIN {
   ... do stuff ...
}

1;
It goes without saying that setup should be done in configure if possible, but if not then this function provides an opportunity.

Of course extensions that require this function will not be compatible with TWiki < 4.2

-- Contributors: CrawfordCurrie, SvenDowideit

Discussion

I can feel the advantage of this, but a concrete example would be good.

-- RafaelAlvarez - 30 Apr 2007

Incorporated Sven's perspicacious BEGIN observation.

Raf, consider the simplest possible cases;

  1. I want to list the version numbers of all installed contribs.
  2. I want to load an extension to a standard TWiki module
Let's say I'm writing a compatability contrib for an old rev of TWiki. I want to add a splurge function to TWiki::Func, and I want to add a new system tag called %CONTRIBVERSIONS%.
package TWiki::Contrib::BlahContrib;

use vars qw($VERSION $RELEASE);

$VERSION = '$Rev$';
$RELEASE = 'TWiki-4';

BEGIN {
   # Note that this is another approach to an issue addressed by Meredith in her TWikiFns work.
   TWiki::registerTagHandler(\&CONTRIBVERSIONS);
};

sub CONTRIBVERSIONS {
    #my ($session, \%params, $web, $topic ) = @_;
    return join(' ',
        map {
            $_.':'.($TWiki::cfg{Contribs}{$_}{Enabled} ? eval '$'.$TWiki::cfg{Contribs}{$_}.'::VERSION' : '(disabled)');
        } keys(%{$TWiki::cfg{Contribs}});
}

# Extend TWiki::Func
package TWiki::Func;

sub splurge {
   # implement the splurge function
}

1;
All that's required is the same sort of discover/enable mechanism as exists for plugins in configure, and to add this to the end of the BEGIN block in TWiki.pm:
foreach my $contrib ( keys(%{$TWiki::cfg{Contribs}} ) {
    next unless $TWiki::cfg{Contribs}{$contrib}{Enabled};
    eval "use TWiki::Contrib::$contrib";
    die "Error loading $module: $@" if $@;
}
i.e. a very low code burden.

-- CrawfordCurrie - 01 May 2007

BEGIN blocks are executed only once in perl accelerators and initializers might need to initialize based on the current request.

Why not making such a contrib a plugin where the needed callback infrastructure exists?

(just asking to test your good idea)

-- MichaelDaum - 01 May 2007

I do not think there is a problem for contribs which need to initialise. The problem arises if they need to register a callback. For that they need to be compiled first, but in contrast to a plugin there is no canonical place where to put the use statement for a contrib. Whenever they are compiled, they can do their initialisation on the way.

This is what you get with an {Enabled} key: Control whether and when the contrib will be compiled, and therefore when its global initialisation is being called. You need it if you want to register a tag handler without having to write a plugin, i.e. without having to deliver an initPlugin per-request initialisation handler.

But this suggestion comes at a price: If TWiki.pm compiles all "enabled" contribs, regardless of whether they are needed for a particular request, then this will slow down things in a non-persistent interpreter, unless authors introduce an extra stub to allow for dynamic compilation within their contrib. So if there is a %CONTRIBVERSIONS% tag, which is pretty unlikely to appear in many topics, it might better do such a discovery itself.

BTW: A BEGIN block is not needed in the given situation. The statements are executed when the module is compiled without the block, and exactly once with persistent interpreters for the same reason. You'd only need a BEGIN block if the rest of the module would need the result of the block at compile time.

-- HaraldJoerg - 01 May 2007

You can think a contrib as a module that by definition is always compiled (if enabled). Most contribs (e.g. skins) will have very light compilation loads, because all they do is define a couple of variables. Others will have a heavy load, for example to install some fancy cache, or replace some big chunk of TWiki code. I think it's perfectly reasonable that well written heavyweight contribs should lazy compile as you describe. I don't really see the 'price' as something anyone can avoid paying.

(for an example of how awkward it currently is to inject contrib code, look at how the JSCalendarContrib is used in Form.pm)

-- CrawfordCurrie - 06 May 2007

No good example: The way how JSCalendarContrib is used in Form.pm is not awkward, it is broken. A require will simply die if the module in question isn't available, The require in Form.pm is not wrapped in eval, so examining $@ is pretty useless.

But let's nevertheless examine the situation in Form.pm: A core module finds an item (in this case: a 'date' field) which it can not handle itself. The current implementation just knows that it should try to fire up JSCalendarContrib.

How would initialising or "enabling" the Contrib help? Well - the code could get rid of the require statement in Form.pm. And simply call the method, praying that the module has been compiled elsewhere. It still would need to know which method to call. Not a big progress.

More flexibility can only be achieved if Form.pm would, for example, throw a well-named exception describing its pain "I have a data type I don't know - Help!". A routine catching this exception could then check whether there's a handler for this type of error. But again, it would not need a precompiled module to find out, a simple entry in %TWiki::cfg could do. These entries are created by configure, which already does discovery (and performance does not matter). So only if the situation occurs and there's a handler for it and the Contrib is enabled it would be compiled.

I haven't looked thoroughly through the skins, but those I have looked at either have no need for compilation at all (e.g. Dandruff) or are good enough as plugins (e.g. Nat).

So what remains to look at is Contribs which override TWiki code. These need to be explicitly compiled, otherwise TWiki would ignore the Contrib and handle stuff as it always did. Would there be any problems if such "Contribs" would simply be implemented as Plugins and use the existing mechanisms?

-- HaraldJoerg - 06 May 2007

The JSCalendarContrib is the only example I have, because it's an example where a contrib has been pulled into the core to avoid the overhead of plugin discovery (the DateFieldPlugin used to do this, but was obsoleted).

OK, in the absence of a strong counter-argument I have to agree with you; the only possible requirement is for %CONTRIBVERSIONS and that's really not a strong enough requirement to justify unconditional compiles. Let's just address these case-by-case. I have re-used Bugs:Item3997 for a couple of the issues raised in the discussion above.

Good debate! Thanks!

-- CrawfordCurrie - 08 May 2007

Edit | Attach | Watch | Print version | History: r12 < r11 < r10 < r9 < r8 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r12 - 2007-05-08 - CrawfordCurrie
 
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.