Skip to content

Commit

Permalink
Item14152: First class replacement implementation.
Browse files Browse the repository at this point in the history
Implemented with Moo::Role create_class_with_roles. Foswiki::Config has
been choosen as the first victim.  An example extension class
Foswiki::Extension::Sample::Class overrides its assignGLOB() method and
instead of aliasing %Foswiki::cfg into $Foswiki::app->cfg->data it ties the
global.

This implementation is only an example. The module will later be deleted
from the repository. The real implementation would make sense if we decide
to move the config into a database, for example. In this case direct
references to Foswiki::Config data attribute must be replaced with calls to
get/set/delete/etc. method calls.
  • Loading branch information
vrurg committed Sep 7, 2016
1 parent d12ad13 commit dee0f93
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 17 deletions.
14 changes: 9 additions & 5 deletions core/lib/Foswiki/App.pm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use Storable qw(dclone);
# shortcut functions. Must be replaced with something more reasonable.
use CGI ();
use Compress::Zlib;
use Foswiki::Extensions;
use Foswiki::Engine;
use Foswiki::Templates;
use Foswiki::Exception;
Expand Down Expand Up @@ -77,6 +78,7 @@ has cache => (
);

=begin TML
---++ ObjectAttribute cfg
This attribute stores application configuration object - a =Foswiki::Config=
Expand Down Expand Up @@ -610,7 +612,7 @@ sub create {
my $this = shift;
my $class = shift;

$class = ref($class) if ref($class);
$class = $this->extensions->mapClass($class);

Foswiki::load_class($class);

Expand Down Expand Up @@ -1542,7 +1544,9 @@ sub _prepareUser {

sub _prepareExtensions {
my $this = shift;
return $this->create('Foswiki::Extensions');

# Don't use create() here because the latter depends on extensions.
return Foswiki::Extensions->new( app => $this );
}

# If the X-Foswiki-Tickle header is present, this request is an attempt to
Expand Down Expand Up @@ -2241,7 +2245,7 @@ sub eachMembership {

=begin TML
---+++ eachGroupMember($group) -> $iterator
---+++ ObjectMethod eachGroupMember($group) -> $iterator
Get an iterator over all the members of the named group. Returns undef if
$group is not a valid group. Nested groups are expanded unless the
expand option is set to false.
Expand Down Expand Up @@ -2282,7 +2286,7 @@ sub eachGroupMember {

=begin TML
---+++ addUserToGroup( $id, $group, $create ) -> $boolean
---+++ ObjectMethod addUserToGroup( $id, $group, $create ) -> $boolean
* $id can be a login name or a WikiName
Expand All @@ -2304,7 +2308,7 @@ sub addUserToGroup {

=begin TML
---+++ removeUserFromGroup( $group, $id ) -> $boolean
---+++ ObjectMethod removeUserFromGroup( $group, $id ) -> $boolean
* $id can be a login name or a WikiName
Expand Down
20 changes: 20 additions & 0 deletions core/lib/Foswiki/Extension/Empty.pm
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# See bottom of file for license and copyright information

package Foswiki::Extension::Empty;

use Foswiki::Class qw(extension);
Expand All @@ -11,3 +13,21 @@ extAfter qw(Sample);
extBefore qw(Test1 Foswiki::Extension::Test2);

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2016 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. For
more details read LICENSE in the root of this distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As per the GPL, removal of this notice is prohibited.
21 changes: 20 additions & 1 deletion core/lib/Foswiki/Extension/Sample.pm
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# See bottom of file for license and copyright information

package Foswiki::Extension::Sample;

Expand All @@ -11,8 +12,26 @@ plugBefore 'Foswiki::Exception::transmute' => sub {

};

extClass 'Foswiki::Logger', 'Foswiki::Extension::Sample::Logger';
extClass 'Foswiki::Config', 'Foswiki::Extension::Sample::Config';

extBefore qw(Empty);

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2016 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. For
more details read LICENSE in the root of this distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As per the GPL, removal of this notice is prohibited.
116 changes: 116 additions & 0 deletions core/lib/Foswiki/Extension/Sample/Config.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# See bottom of file for license and copyright information

package Foswiki::Extension::Sample::TiedConfig;
use Assert;

sub TIEHASH {
my $class = shift;
my ($cfgObject) = @_;

my $thisHash = { cfg => $cfgObject, };

return bless $thisHash, $class;
}

sub FETCH {
my ( $this, $key ) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
$this->trace("FETCH{$key}");
return $this->{cfg}->data->{$key};
}

sub STORE {
my ( $this, $key, $value ) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
$this->trace("STORE{$key}");
$this->{cfg}->data->{$key} = $value;
}

sub DELETE {
my ( $this, $key ) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
$this->trace("DELETE{$key}");
delete $this->{cfg}->data->{$key};
}

sub CLEAR {
my ($this) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
$this->{cfg}->clear_data;
}

sub EXISTS {
my ( $this, $key ) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
return exists $this->{cfg}->data->{$key};
}

sub FIRSTKEY {
my ($this) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
my $_ignore = keys %{ $this->{cfg}->data };
return each %{ $this->{cfg}->data };
}

sub NEXTKEY {
my ($this) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
return each %{ $this->{cfg}->data };
}

sub SCALAR {
my ($this) = @_;
ASSERT( defined $this->{cfg} ) if DEBUG;
return scalar %{ $this->{cfg}->data };
}

sub UNTIE {
my ($this) = @_;

undef $this->{cfg};
}

sub setTrace {
my $this = shift;
$this->{_trace} = shift;
}

sub trace {
my $this = shift;
if ( $this->{_trace} ) {
say STDERR @_;
}
}

package Foswiki::Extension::Sample::Config;

use Moo::Role;

around assignGLOB => sub {
my $orig = shift;
my $this = shift;

say STDERR "This is a replacement assignGLOB method.";

tie %Foswiki::cfg, 'Foswiki::Extension::Sample::TiedConfig', $this;
};

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2016 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. For
more details read LICENSE in the root of this distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As per the GPL, removal of this notice is prohibited.
64 changes: 57 additions & 7 deletions core/lib/Foswiki/Extensions.pm
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ sub BUILD {
say STDERR "Initializing extensions" if DEBUG;

$this->load_extensions;
$this->registeredClasses;

say STDERR "Ext sub classes: ", Dumper( \%extSubClasses );
say STDERR "Ext deps: ", Dumper( \%extDeps );
#$this->registeredClasses;
#
#say STDERR "Ext sub classes: ", Dumper( \%extSubClasses );
#say STDERR "Ext deps: ", Dumper( \%extDeps );
}

sub normalizeExtName {
Expand Down Expand Up @@ -391,9 +392,28 @@ sub disableExtension {

=begin TML
---++ ObjectMethod listDisabledExtensions => @list
---++ ObjectMethod mapClass($class) => $replacement
Returns a list of extensions disabled for this installation or host.
Maps a core class name into replacement class name.
=cut

sub mapClass {
my $this = shift;
my ($class) = @_;

$class = ref($class) || $class;

my $replClass = $this->registeredClasses->{$class};
return $replClass || $class;
}

=begin TML
---++ ObjectMethod prepareDisabledExtensions => \%disabled
Returns extensions disabled for this installation or host. %disabled hash keys
are extension names, values are text reasons for disabling the extension.
=cut

Expand Down Expand Up @@ -462,15 +482,33 @@ sub prepareRegisteredClasses {
}
}

foreach my $extName ( @{ $this->orderedList } ) {
# Build inheritance order. Use reverse to conform with the way overriden
# methods are getting called.
my %inheritance;
foreach my $extName ( reverse @{ $this->orderedList } ) {
foreach my $coreClass ( keys %{ $ext2class{$extName} } ) {
push @{ $classMap{$coreClass} }, $ext2class{$extName}{$coreClass};
push @{ $inheritance{$coreClass} },
$ext2class{$extName}{$coreClass};
}
}

# Build actual replacement classes.
foreach my $coreClass ( keys %inheritance ) {
( my $crypticName = $coreClass ) =~ s/::/__/;
$classMap{$coreClass} =
Moo::Role->create_class_with_roles( $coreClass,
@{ $inheritance{$coreClass} } );
}

return \%classMap;
}

=begin TML
---++ Static methods
=cut

sub registerSubClass {
my ( $extModule, $class, $subClass ) = @_;

Expand Down Expand Up @@ -500,6 +538,18 @@ sub isRegistered {
return $registeredModules{$extModule} // 0;
}

sub genClassName {
my ($nameTmpl) = @_;

state $seqNum = 0;

my $nameFmt = $nameTmpl // 'Foswiki::Class::_AutoXXXXX';

$nameFmt =~ s/(X{3,})/"%0" . length($1) . "d"/e;

return sprintf( $nameFmt, $seqNum );
}

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Expand Down
3 changes: 1 addition & 2 deletions core/lib/Foswiki/Logger/Compatibility.pm
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ BEGIN {

# Internal class for Logfile iterators.
# So we don't break encapsulation of file handles. Open / Close in same file.
use Moo;
use namespace::clean;
use Foswiki::Class;
extends qw(Foswiki::Iterator::EventIterator);

has logLocked => (
Expand Down
3 changes: 1 addition & 2 deletions core/lib/Foswiki/Logger/PlainFile.pm
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ BEGIN {

# Internal class for Logfile iterators.
# So we don't break encapsulation of file handles. Open / Close in same file.
use Moo;
use namespace::clean;
use Foswiki::Class;
extends qw(Foswiki::Iterator::EventIterator);

has handle => ( is => 'rw', );
Expand Down

0 comments on commit dee0f93

Please sign in to comment.