Skip to content

Commit

Permalink
Item13897: API functions are moved to Foswiki::App.
Browse files Browse the repository at this point in the history
All Foswiki::Func::* functions, except for deprecated ones, are either
moved to Foswiki.pm if they're purely static. Otherwise they're made
Foswiki::App methods except for a few defined in %_funcPrefixMap which are
new methods of other classes where they natively belong.

The purpose of this move is to minize use of the global $Foswiki::app and
%Foswiki::cfg variables.

Note Foswiki::Func maps moved functions using AUTOLOAD(). If a function
gets called it gets generated using pretty simple code of checking if
$Foswiki::app is defined and then calling corresponding method on it.

AUTOLOAD() takes care of deprecated functions too. If it detects that
function is still present in Foswiki::Func namespace and has '_deprecated_'
prefix in its name then the code generated for the function will log a
warning about use of a deprecation each time it gets called.

- Foswiki::Aux::Holder can now use a object of any class with restore()
method defined.

- To be noted: Foswiki::Configure::Pluggables::SCRIPTHASH is using
$Foswiki::engine in a regex. The variable isn't there anymore and the whole
approach has been changed. Must be reconsidered.

- Clean up of search/query methods parameters of modules in Foswiki::Store
family: removed $app parameter and using object's app attribute instead.

- Converted static _search() methods of Foswiki::Store::SearchAlgorythms
into object methods.

- Added reason object attribute on Foswiki::Meta. Must be given preference
over $Foswiki::Meta::reason whenever possible. Though upon change the
attribute sets the global variable to the same value.
  • Loading branch information
vrurg committed Aug 2, 2016
1 parent aff6e75 commit 2b56d1a
Show file tree
Hide file tree
Showing 25 changed files with 2,733 additions and 1,706 deletions.
16 changes: 9 additions & 7 deletions JsonRpcContrib/lib/Foswiki/Contrib/JsonRpcContrib/Server.pm
Expand Up @@ -46,14 +46,15 @@ has handler => ( is => 'rw', lazy => 1, default => sub { {} }, );
################################################################################
# static
sub writeDebug {
Foswiki::Func::writeDebug '- JsonRpcContrib::Server - ' . $_[0];

This comment has been minimized.

Copy link
@MichaelDaum

MichaelDaum Aug 3, 2016

Member

Did you just empty Foswiki::Func??? That's not a good idea. It is the most common interface for any plugin that we tried to preserve while the engine underneath was changing during the years.

This comment has been minimized.

Copy link
@vrurg

vrurg Aug 3, 2016

Author Member

Sorry if my commit message wasn't clear. Foswiki::Func is mapping from App into its own namespace using AUTOLOAD. compatibility wasn't hurt, FuncTests is still passing.

This comment has been minimized.

Copy link
@MichaelDaum

MichaelDaum Aug 3, 2016

Member

Ah okay. Then how does that work out specifically?

This comment has been minimized.

Copy link
@KennethLavrsen

KennethLavrsen via email Aug 3, 2016

Member

This comment has been minimized.

Copy link
@gac410

gac410 via email Aug 3, 2016

Member

This comment has been minimized.

Copy link
@KennethLavrsen

KennethLavrsen via email Aug 3, 2016

Member

This comment has been minimized.

Copy link
@gac410

gac410 via email Aug 3, 2016

Member

This comment has been minimized.

Copy link
@vrurg

vrurg Aug 3, 2016

Author Member

Kenneth, in addition to what George wrote, I would add just one more note: the point of converting API functions into methods is to step further on the road from global variables to fully incapsulated objects. Thus easing Foswiki life in shared environments. It's not easy to write extensive explanations from iPad, but you may try reading about PSGI delayed response. It would demand few copies of Foswiki app to coexist within single process. it would be possible to dynamically switch globals like $Foswiki::app and $Foswiki::cfg, but the approach is flawed.

Minor issue with filling the logs with the warning message could easily be fixed in few ways. Anyway Foswiki::Func itself has to be deprecated.

And finally to the most important problem of it all: Kenneth, I currently exist in vacuum. There are few topics on the OO, where I do expect for feedback. There are release meetings where nobody but Michael and George to talk to. So, I do what I think is correct because of no feedback. And when I do it what do I get? You blaming me?

I'm stuck. I need help to continue. Do you want me to stop now? Ok, that's the easiest thing to do.

Or we can have the thing done. And then I can take care of all the plugins you're worried about.

This comment has been minimized.

Copy link
@KennethLavrsen

KennethLavrsen via email Aug 3, 2016

Member

This comment has been minimized.

Copy link
@MichaelDaum

MichaelDaum Aug 4, 2016

Member

This discussion is totally at the wrong place.

Please, read https://foswiki.org/Development/NewOODesignPlan, https://foswiki.org/Development/MooFoswikiPm, https://foswiki.org/Development/Foswiki3CodeChanges and a few more. Feel encouraged to comment there. Join the daily discussions on IRC and Slack. Do participate in our bi-weekly release meetings where we regularly discuss the OO-rewrite and a lot more.

Next release meeting will be on 2016-08-08. The logs of all previous meetings are at https://foswiki.org/Development/ReleaseMeetings

my $this = shift;
$this->app->writeDebug( '- JsonRpcContrib::Server - ' . $_[0] );
}

################################################################################
sub registerMethod {
my ( $this, $namespace, $method, $fnref, $options ) = @_;

writeDebug("registerMethod($namespace, $method, $fnref)") if TRACE;
$this->writeDebug("registerMethod($namespace, $method, $fnref)") if TRACE;

$this->handler->{$namespace}{$method} = {
function => $fnref,
Expand All @@ -68,7 +69,7 @@ sub dispatch {

my $app = $ui->app;

writeDebug("called dispatch") if TRACE;
$this->writeDebug("called dispatch") if TRACE;

my $request = $app->request;

Expand All @@ -90,7 +91,7 @@ sub dispatch {
$topic );
$app->request->web($jsrpcWeb);
$app->request->topic($jsrpcTopic);
writeDebug("topic=$topic") if TRACE;
$this->writeDebug("topic=$topic") if TRACE;

# get handler for this namespace
my $handler = $this->getHandler($request);
Expand All @@ -109,7 +110,7 @@ sub dispatch {
# if there's login info, try and apply it
my $userName = $request->param('username');
if ($userName) {
writeDebug("checking password for $userName") if TRACE;
$this->writeDebug("checking password for $userName") if TRACE;
my $pass = $request->param('password') || '';
unless ( $app->users->checkPassword( $userName, $pass ) ) {
Foswiki::Contrib::JsonRpcContrib::Response->print(
Expand Down Expand Up @@ -155,7 +156,7 @@ sub dispatch {
try {
no strict 'refs';
my $function = $handler->{function};
writeDebug( "calling handler for "
$this->writeDebug( "calling handler for "
. $request->namespace . "."
. $request->jsonmethod )
if TRACE;
Expand Down Expand Up @@ -242,7 +243,8 @@ sub getHandler {
my $def =
$Foswiki::cfg{JsonRpcContrib}{Handler}{$namespace}{$method};

writeDebug("compiling $def->{package} for $namespace.$method")
$this->writeDebug(
"compiling $def->{package} for $namespace.$method")
if TRACE;
eval qq(use $def->{package});

Expand Down
6 changes: 4 additions & 2 deletions PlainFileStoreContrib/lib/Foswiki/Store/PlainFile.pm
Expand Up @@ -861,7 +861,9 @@ sub remove {

# Implement Foswiki::Store
sub query {
my ( $this, $query, $inputTopicSet, $app, $options ) = @_;
my ( $this, $query, $inputTopicSet, $options ) = @_;

my $app = $this->app;

my $searchEngine;
if ( $query->isa('Foswiki::Query::Node') ) {
Expand Down Expand Up @@ -904,7 +906,7 @@ sub query {
}

no strict 'refs';
return $searchEngine->query( $query, $inputTopicSet, $app, $options );
return $searchEngine->query( $query, $inputTopicSet, $options );
use strict 'refs';
}

Expand Down
4 changes: 2 additions & 2 deletions RCSStoreContrib/lib/Foswiki/Store/Rcs/Store.pm
Expand Up @@ -640,7 +640,7 @@ sub remove {
}

sub query {
my ( $this, $query, $inputTopicSet, $session, $options ) = @_;
my ( $this, $query, $inputTopicSet, $options ) = @_;

my $engine;
if ( $query->isa('Foswiki::Query::Node') ) {
Expand Down Expand Up @@ -668,7 +668,7 @@ sub query {
}

no strict 'refs';
return $engine->query( $query, $inputTopicSet, $session, $options );
return $engine->query( $query, $inputTopicSet, $options );
use strict 'refs';
}

Expand Down
4 changes: 3 additions & 1 deletion UnitTestContrib/lib/Unit/PlackTestCase.pm
Expand Up @@ -168,7 +168,9 @@ sub _genDefaultAppSub {
eval {
require Devel::MAT::Dumper;
Devel::MAT::Dumper::dump( $FindBin::Bin
. "/../working/logs/foswiki_debug_psgi.pmat" );
. "/../working/logs/"
. $this->testSuite
. ".pmat" );
};
}

Expand Down
2 changes: 1 addition & 1 deletion UnitTestContrib/test/bin/TestRunner.pl
Expand Up @@ -8,7 +8,6 @@
use FindBin;
use Cwd ();
use File::Path ();
require Unit::TestApp;
my $starting_root;

# Simplify debugging by making both stderr and stdout non-buffered.
Expand Down Expand Up @@ -63,6 +62,7 @@ BEGIN
# to avoid compiling Foswiki.pm before FOSWIKI_ASSERTS have been set
#use Foswiki; # If you take this out then TestRunner.pl will fail on IndigoPerl
use Unit::TestRunner;
use Unit::TestApp;

my %options;
while ( scalar(@ARGV) && $ARGV[0] =~ /^-/ ) {
Expand Down
4 changes: 2 additions & 2 deletions UnitTestContrib/test/unit/FuncTests.pm
Expand Up @@ -2602,7 +2602,7 @@ sub test_query {
{ web => 'System', casesensitive => 0, files_without_match => 0 } );

$this->assert( $matches->hasNext )
; #gosh i hope we alway have a document with the word broken in it..
; #gosh i hope we always have a document with the word broken in it..
my $webtopic = $matches->next;
my ( $web, $searchTopic ) =
Foswiki::Func::normalizeWebTopicName( '', $webtopic );
Expand Down Expand Up @@ -2685,7 +2685,7 @@ sub test_writeEvent {
Foswiki::Func::writeEvent("bacon");
Foswiki::Func::writeEvent();
Foswiki::Func::writeEvent( "toast", "jam" );
my $it = Foswiki::Func::eachEventSince($now);
my $it = $this->app->logger->eachEventSince( $now, 'info' );
$this->assert( $it->hasNext() );
my $e = $it->next();
$this->assert_equals( $now, $e->[0] );
Expand Down
2 changes: 1 addition & 1 deletion UnitTestContrib/test/unit/HTMLValidationTests.pm
Expand Up @@ -29,7 +29,7 @@ my %expected_status = (
restauth => 404,
resetpasswd => 400, # LoginName parameter required but not passed.
manage => 400, # See TODO comment below.
upload => 400, # See TODO comment below.
upload => 302, # See TODO comment below.
register => 501, # See TODO comment below.
);

Expand Down
181 changes: 119 additions & 62 deletions core/lib/Foswiki.pm
Expand Up @@ -6,44 +6,10 @@ use v5.14; # First version to accept v-numbers.
---+ package Foswiki
Foswiki operates by creating a singleton object (known as the Session
object) that acts as a point of reference for all the different
modules in the system. This package is the class for this singleton,
and also contains the vast bulk of the basic constants and the per-
site configuration mechanisms.
Global variables are avoided wherever possible to avoid problems
with CGI accelerators such as mod_perl.
---++ Public Data members
* =request= Pointer to the Foswiki::Request
* =response= Pointer to the Foswiki::Response
* =context= Hash of context ids
* =plugins= Foswiki::Plugins singleton
* =prefs= Foswiki::Prefs singleton
* =remoteUser= Login ID when using ApacheLogin. Maintained for
compatibility only, do not use.
* =requestedWebName= Name of web found in URL path or =web= URL parameter
* =scriptUrlPath= URL path to the current script. May be dynamically
extracted from the URL path if {GetScriptUrlFromCgi}.
Only required to support {GetScriptUrlFromCgi} and
not consistently used. Avoid.
* =access= Foswiki::Access singleton
* =store= Foswiki::Store singleton
* =topicName= Name of topic found in URL path or =topic= URL
parameter
* =urlHost= Host part of the URL (including the protocol)
determined during intialisation and defaulting to
{DefaultUrlHost}
* =user= Unique user ID of logged-in user
* =users= Foswiki::Users singleton
* =webName= Name of web found in URL path, or =web= URL parameter,
or {UsersWebName}
=cut

use Cwd qw( abs_path );
use Module::Load;
use File::Spec ();
use Monitor ();
use CGI (); # Always required to get html generation tags;
Expand All @@ -67,7 +33,6 @@ our $RELEASE;
our $UNICODE = 1; # flag that extensions can use to test if the core is unicode
our $TRUE = 1;
our $FALSE = 0;
our $engine;
our $TranslationToken = "\0"; # Do not deprecate - used in many plugins
our $system_message; # Important broadcast message from the system
my $bootstrap_message = ''; # Bootstrap message.
Expand Down Expand Up @@ -99,7 +64,8 @@ use Try::Tiny;
use Assert;
use Exporter qw(import);
our @EXPORT_OK =
qw(%regex urlEncode urlDecode make_params load_package load_class expandStandardEscapes);
qw(%regex urlEncode urlDecode make_params load_package load_class
expandStandardEscapes findCaller findCallerByPrefix isTrue);

sub SINGLE_SINGLETONS { 0 }
sub SINGLE_SINGLETONS_TRACE { 0 }
Expand Down Expand Up @@ -256,32 +222,6 @@ sub splitAnchorFromUrl {

=begin TML
---++ ObjectMethod getCGISession() -> $cgisession
Get the CGI::Session object associated with this session, if there is
one. May return undef.
=cut

sub getCGISession {
$_[0]->users->getCGISession();
}

=begin TML
---++ ObjectMethod getLoginManager() -> $loginManager
Get the Foswiki::LoginManager object associated with this session, if there is
one. May return undef.
=cut

sub getLoginManager {
$_[0]->users->getLoginManager();
}

=begin TML
---++ StaticMethod isValidWikiWord( $name ) -> $boolean
Check for a valid WikiWord or WikiName
Expand Down Expand Up @@ -847,6 +787,123 @@ sub putBackBlocks {

}

=begin TML
---++ StaticMethod findCaller($regex, $negate) -> $moduleName || undef
Returns first module name matching =$regex= found in the call stack as given
by Perl function =caller()=. Returns undef if no module matching the regex
found.
If =$negate= is true than the first module which doesn't match is returned.
=cut

sub findCaller {
my ( $regex, $negate ) = @_;

my $level = 1;
while ( defined( my $modName = caller($level) ) ) {
my $found = $modName =~ $regex;
$found = !$found if $negate;
if ($found) {
return wantarray ? ( $modName, $level ) : $modName;
}
$level++;
}

return undef;
}

=begin TML
---++ StaticMethod findCallerByPrefix($prefix) -> $moduleName || undef
Returns first module name which name starts with $prefix found in the call stack
as returned by Perl function =caller()=. Returns undef if no module with the
prefix is found.
=cut

sub findCallerByPrefix {
my $prefix = shift;

my $match = qr/^\Q$prefix\E/;
return findCaller($match);
}

=begin TML
---+++ StaticMethod readFile( $filename, $unicode ) -> $text
Read file, low level. Used for Plugin workarea.
* =$filename= - Full path name of file
* =$unicode= - Specify that file contains unicode text *New with Foswiki 2.0*
Return: =$text= Content of file, empty if not found
__NOTE:__ Use this function only for the Plugin workarea, *not* for topics and attachments. Use the appropriate functions to manipulate topics and attachments.
Foswiki 2.0 APIs generally all use UNICODE strings, and all data is properly decoded from/to utf-8 at the edge. *This API is an exception!*
Because this API can be used to retrieve data of any type including binary data, it is *not* decoded to unicode by default.
By default, data is read as raw bytes, without any encoding layer.
If you are using this API to read topic originated data, topic names, etc. then you should set the =$unicode= flag so that the data returned is a valid perl character string.
=cut

sub readFile {
my ( $name, $unicode ) = @_;
my $data = '';
my $IN_FILE;
open( $IN_FILE, '<', $name ) || return '';

if ($unicode) {
binmode $IN_FILE, ':encoding(utf-8)';
}
local $/ = undef; # set to read to EOF
$data = <$IN_FILE>;
close($IN_FILE);
$data = '' unless $data; # no undefined
return $data;
}

=begin TML
---+++ StaticMethod saveFile( $filename, $text, $unicode )
Save file, low level. Used for Plugin workarea.
* =$filename= - Full path name of file
* =$text= - Text to save
* =$unicode= - Flag indicates that $text string should be saved as utf-8. *New with Foswiki 2.0*
Return: none
__NOTE:__ Use this function only for the Plugin workarea, *not* for topics and attachments. Use the appropriate functions to manipulate topics and attachments.
Foswiki 2.0 APIs generally all use UNICODE strings, and all data is properly decoded from/to utf-8 at the edge. *This API is an exception!*
Because this API can be used to save data of any type including binary data, it is *not* decoded to unicode by default.
By default, data is written as raw bytes, without any encoding layer.
If you are using this API to write topic data, topic names, etc. then you should set the =$unicode= flag so that the data returned as a valid perl character string.
Failure to set the =$unicode= flag when required will result in perl "Wide character in print" errors.
=cut

sub saveFile {
my ( $name, $text, $unicode ) = @_;
my $FILE;
unless ( open( $FILE, '>', $name ) ) {
die "Can't create file $name - $!\n";
}

if ($unicode) {
binmode $FILE, ':encoding(utf-8)';
}
print $FILE $text;
close($FILE);
}

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Expand Down

0 comments on commit 2b56d1a

Please sign in to comment.