Add mw.message library

Change-Id: I12ca84f848c34f1227ee8acdc8bc04bdfd0b2d97
This commit is contained in:
Brad Jorsch 2013-02-08 09:56:44 -05:00 committed by Chad Horohoe
parent 07d6ed437a
commit ba09ba3fde
7 changed files with 404 additions and 0 deletions

View file

@ -107,6 +107,7 @@ $wgAutoloadClasses['Scribunto_LuaSiteLibrary'] = $dir.'engines/LuaCommon/SiteLib
$wgAutoloadClasses['Scribunto_LuaUriLibrary'] = $dir.'engines/LuaCommon/UriLibrary.php';
$wgAutoloadClasses['Scribunto_LuaUstringLibrary'] = $dir.'engines/LuaCommon/UstringLibrary.php';
$wgAutoloadClasses['Scribunto_LuaLanguageLibrary'] = $dir.'engines/LuaCommon/LanguageLibrary.php';
$wgAutoloadClasses['Scribunto_LuaMessageLibrary'] = $dir.'engines/LuaCommon/MessageLibrary.php';
/***** Configuration *****/

View file

@ -301,6 +301,7 @@ WIKI;
'engines/LuaCommon/SiteLibraryTest.php',
'engines/LuaCommon/UriLibraryTest.php',
'engines/LuaCommon/UstringLibraryTest.php',
'engines/LuaCommon/MessageLibraryTest.php',
);
foreach ( $tests as $test ) {
$files[] = dirname( __FILE__ ) .'/../tests/' . $test;

View file

@ -10,6 +10,7 @@ abstract class Scribunto_LuaEngine extends ScribuntoEngineBase {
'mw.uri' => 'Scribunto_LuaUriLibrary',
'mw.ustring' => 'Scribunto_LuaUstringLibrary',
'mw.language' => 'Scribunto_LuaLanguageLibrary',
'mw.message' => 'Scribunto_LuaMessageLibrary',
);
/**

View file

@ -0,0 +1,74 @@
<?php
class Scribunto_LuaMessageLibrary extends Scribunto_LuaLibraryBase {
function register() {
$lib = array(
'toString' => array( $this, 'messageToString' ),
'check' => array( $this, 'messageCheck' ),
);
// Get the correct default language from the parser
if ( $this->getParser() ) {
$lang = $this->getParser()->getTargetLanguage();
} else {
global $wgContLang;
$lang = $wgContLang;
}
$this->getEngine()->registerInterface( 'mw.message.lua', $lib, array(
'lang' => $lang->getCode(),
) );
}
private function makeMessage( $data, $setParams ) {
if ( isset( $data['rawMessage'] ) ) {
$msg = new RawMessage( $data['rawMessage'] );
} else {
$msg = Message::newFallbackSequence( $data['keys'] );
}
$msg->inLanguage( $data['lang'] )
->useDatabase( $data['useDB'] );
if ( $setParams ) {
if ( isset( $data['title'] ) ) {
$title = Title::newFromText( $data['title'] );
} else {
$title = $this->getTitle();
}
$msg->params( array_values( $data['params'] ) )
->title( $title );
}
return $msg;
}
function messageToString( $format, $data ) {
if ( !in_array( $format, array( 'parse', 'text', 'plain', 'escaped', 'parseAsBlock' ) ) ) {
throw new Scribunto_LuaError( "invalid format for 'messageToString'" );
}
if ( in_array( $format, array( 'parse', 'parseAsBlock' ) ) ) {
// Limit calls into the full parser
$this->incrementExpensiveFunctionCount();
}
try {
$msg = $this->makeMessage( $data, true );
return array( call_user_func( array( $msg, $format ) ) );
} catch( MWException $ex ) {
throw new Scribunto_LuaError( "msg:$format() failed (" . $ex->getMessage() . ")" );
}
}
function messageCheck( $what, $data ) {
if ( !in_array( $what, array( 'exists', 'isBlank', 'isDisabled' ) ) ) {
throw new Scribunto_LuaError( "invalid what for 'messageCheck'" );
}
try {
$msg = $this->makeMessage( $data, false );
return array( call_user_func( array( $msg, $what ) ) );
} catch( MWException $ex ) {
throw new Scribunto_LuaError( "msg:$what() failed (" . $ex->getMessage() . ")" );
}
}
}

View file

@ -0,0 +1,231 @@
local message = {}
local php
local util = require 'libraryUtil'
local checkType = util.checkType
local valuemt = {
__tostring = function ( t )
return tostring( t.raw or t.num )
end
}
local function checkScalar( name, argIdx, arg, level, valuemtOk )
local tp = type( arg )
-- If special params are ok, detect them
if valuemtOk and tp == 'table' and getmetatable( arg ) == valuemt then
return arg
end
-- If it's a table with a custom __tostring function, use that string
if tp == 'table' and getmetatable( arg ) and getmetatable( arg ).__tostring then
return tostring( arg )
end
if tp ~= 'string' and tp ~= 'number' then
error( string.format(
"bad argument #%d to '%s' (string or number expected, got %s)",
argIdx, name, tp
), level + 1 )
end
return arg
end
local function checkParams( name, valueOk, ... )
-- Accept an array of params, or params as individual command line arguments
local params, nparams
local first = select( 1, ... )
if type( first ) == 'table' and
not ( getmetatable( first ) and getmetatable( first ).__tostring )
then
if select( '#', ... ) == 1 then
params = first
nparams = table.maxn( params )
else
error(
"bad arguments to '" .. name .. "' (pass either a table of params or params as individual arguments)",
3
)
end
else
params = { ... }
nparams = select( '#', ... )
end
for i = 1, nparams do
params[i] = checkScalar( 'params', i, params[i], 3, valueOk )
end
return params
end
function message.setupInterface( options )
-- Boilerplate
message.setupInterface = nil
php = mw_interface
mw_interface = nil
php.options = options
-- Register this library in the "mw" global
mw = mw or {}
mw.message = message
package.loaded['mw.message'] = message
end
local function makeMessage( options )
local obj = {}
local checkSelf = util.makeCheckSelfFunction( 'mw.message', 'msg', obj, 'message object' )
local data = {
keys = options.keys,
rawMessage = options.rawMessage,
params = {},
lang = php.options.lang,
useDB = true,
}
local funcs = {}
function funcs:params( ... )
checkSelf( self, 'params' )
local params = checkParams( 'params', true, ... )
local j = #data.params
for i = 1, #params do
data.params[j + i] = params[i]
end
return self
end
function funcs:rawParams( ... )
checkSelf( self, 'rawParams' )
local params = checkParams( 'rawParams', false, ... )
local j = #data.params
for i = 1, #params do
data.params[j + i] = setmetatable( { raw = params[i] }, valuemt )
end
return self
end
function funcs:numParams( ... )
checkSelf( self, 'numParams' )
local params = checkParams( 'numParams', false, ... )
local j = #data.params
for i = 1, #params do
data.params[j + i] = setmetatable( { num = params[i] }, valuemt )
end
return self
end
function funcs:inLanguage( lang )
checkSelf( self, 'inLanguage' )
if type( lang ) == 'table' and lang.getCode then
-- probably a mw.language object
lang = lang:getCode()
end
checkType( 'inLanguage', 1, lang, 'string' )
data.lang = lang
return self
end
function funcs:useDatabase( value )
checkSelf( self, 'useDatabase' )
checkType( 'useDatabase', 1, value, 'boolean' )
data.useDB = value
return self
end
function funcs:title( title )
checkSelf( self, 'title' )
if type( title ) == 'table' and title.prefixedText then
-- probably a mw.title object
title = title.prefixedText
end
checkType( 'title', 1, title , 'string', true )
data.title = title
return self
end
function funcs:parse()
checkSelf( self, 'parse' )
return php.toString( 'parse', data )
end
function funcs:text()
checkSelf( self, 'text' )
return php.toString( 'text', data )
end
function funcs:plain()
checkSelf( self, 'plain' )
return php.toString( 'plain', data )
end
function funcs:escaped()
checkSelf( self, 'escaped' )
return php.toString( 'escaped', data )
end
function funcs:parseAsBlock()
checkSelf( self, 'parseAsBlock' )
return php.toString( 'parseAsBlock', data )
end
function funcs:exists()
checkSelf( self, 'exists' )
return php.check( 'exists', data )
end
function funcs:isBlank()
checkSelf( self, 'isBlank' )
return php.check( 'isBlank', data )
end
function funcs:isDisabled()
checkSelf( self, 'isDisabled' )
return php.check( 'isDisabled', data )
end
return setmetatable( obj, {
__index = funcs,
__tostring = function ( t )
return t:text()
end
} )
end
function message.new( key, ... )
checkType( 'message.new', 1, key, 'string' )
return makeMessage{ keys = { key } }:params( ... )
end
function message.newFallbackSequence( ... )
for i = 1, math.max( 1, select( '#', ... ) ) do
checkType( 'message.newFallbackSequence', i, select( i, ... ), 'string' )
end
return makeMessage{ keys = { ... } }
end
function message.newRawMessage( msg, ... )
checkType( 'message.newRawMessage', 1, msg, 'string' )
return makeMessage{ rawMessage = msg }:params( ... )
end
function message.rawParam( value )
value = checkScalar( 'message.rawParam', 1, value )
return setmetatable( { raw = value }, valuemt )
end
function message.numParam( value )
value = checkScalar( 'message.numParam', 1, value )
return setmetatable( { num = value }, valuemt )
end
function message.getDefaultLanguage()
if mw.language then
return mw.language.new( php.options.lang )
else
return php.options.lang
end
end
return message

View file

@ -0,0 +1,11 @@
<?php
class Scribunto_LuaMessageLibraryTests extends Scribunto_LuaEngineTestBase {
protected static $moduleName = 'MessageLibraryTests';
function getTestModules() {
return parent::getTestModules() + array(
'MessageLibraryTests' => __DIR__ . '/MessageLibraryTests.lua',
);
}
}

View file

@ -0,0 +1,85 @@
local testframework = require 'Module:TestFramework'
local message1 = mw.message.new( 'mainpage' )
local message1_copy = mw.message.new( 'mainpage' )
local message2 = mw.message.new( 'i-dont-exist-evar' )
function test_exists( key )
return mw.message.new( key ):exists()
end
function test_language( key )
-- If mw.language is available, test that too
local lang = 'ru'
if mw.language then
lang = mw.language.new( 'ru' )
end
return mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( 'en' ):text(),
mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( 'ru' ):text(),
mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( lang ):text()
end
function test_params( rawMessage, func, ... )
local msg = mw.message.newRawMessage( rawMessage ):inLanguage( 'en' )
return msg[func]( msg, ... ):parse()
end
function test_title()
-- If mw.title is available, test that too
local title = 'Main Page'
if mw.title then
title = mw.title.new( title )
end
return mw.message.newRawMessage( '{{PAGENAME}}' ):title( 'Main Page' ):text(),
mw.message.newRawMessage( '{{PAGENAME}}' ):title( title ):text()
end
return testframework.getTestProvider( {
{ name = 'exists (1)', func = test_exists,
args = { 'mainpage' },
expect = { true }
},
{ name = 'exists (2)', func = test_exists,
args = { 'i-dont-exist-evar' },
expect = { false }
},
{ name = 'inLanguage', func = test_language,
expect = { 'Main Page', 'Заглавная страница', 'Заглавная страница' }
},
{ name = 'title', func = test_title,
expect = { 'Main Page', 'Main Page' }
},
{ name = 'plain param', func = test_params,
args = { '($1 $2)', 'params', "'''foo'''", 123456 },
expect = { "(<b>foo</b> 123456)" }
},
{ name = 'raw param', func = test_params,
args = { '($1 $2)', 'rawParams', "'''foo'''", 123456 },
expect = { "('''foo''' 123456)" }
},
{ name = 'num param', func = test_params,
args = { '($1 $2)', 'numParams', "'''foo'''", 123456 },
expect = { "(<b>foo</b> 123,456)" }
},
{ name = 'mixed params', func = test_params,
args = { '($1 $2 $3)', 'params',
"'''foo'''", mw.message.rawParam( "'''foo'''" ), mw.message.numParam( 123456 )
},
expect = { "(<b>foo</b> '''foo''' 123,456)" }
},
{ name = 'message as param', func = test_params,
args = { '($1)', 'params', mw.message.newRawMessage( 'bar' ) },
expect = { "(bar)" }
},
{ name = 'different title', func = test_params,
args = { '($1)', 'params', mw.message.newRawMessage( 'bar' ) },
expect = { "(bar)" }
},
} )