jenkins-bot has submitted this change and it was merged.

Change subject: Add abstract GadgetRepo and MediaWikiGadgetsDefinition 
implementation
......................................................................


Add abstract GadgetRepo and MediaWikiGadgetsDefinition implementation

GadgetRepo is an abstract class based off of the implementation in the
RL2 branch.

It is a singleton that provides basic methods to construct and interact
with Gadget objects.

The MediaWikiGadgetsDefinition class is an implementation of GadgetsRepo
that parses the "MediaWiki:Gadgets-definition" page for gadget
definitions.

Tests were left in place to demonstrate that no functional changes have
been made aside from relocation of code. Some tests should be moved to
separate files in the future.

Bug: T106176
Change-Id: I3e802889f6f495783f4dbac65c2a8cefa824a778
---
M GadgetHooks.php
M Gadgets_body.php
M SpecialGadgets.php
M api/ApiQueryGadgetCategories.php
M api/ApiQueryGadgets.php
M extension.json
A includes/GadgetRepo.php
A includes/MediaWikiGadgetsDefinitionRepo.php
M tests/GadgetTest.php
9 files changed, 342 insertions(+), 261 deletions(-)

Approvals:
  Krinkle: Looks good to me, but someone else must approve
  Alex Monk: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/GadgetHooks.php b/GadgetHooks.php
index efec80a..33a865c 100644
--- a/GadgetHooks.php
+++ b/GadgetHooks.php
@@ -33,8 +33,11 @@
        public static function articleSaveComplete( $article, $user, $text ) {
                // update cache if MediaWiki:Gadgets-definition was edited
                $title = $article->getTitle();
-               if ( $title->getNamespace() == NS_MEDIAWIKI && 
$title->getText() == 'Gadgets-definition' ) {
-                       Gadget::purgeDefinitionCache();
+               $repo = GadgetRepo::singleton();
+               if ( $title->getNamespace() == NS_MEDIAWIKI && 
$title->getText() == 'Gadgets-definition'
+                       && $repo instanceof MediaWikiGadgetsDefinitionRepo
+               ) {
+                       $repo->purgeDefinitionCache();
                }
                return true;
        }
@@ -45,7 +48,7 @@
         * @return bool
         */
        public static function userGetDefaultOptions( &$defaultOptions ) {
-               $gadgets = Gadget::loadStructuredList();
+               $gadgets = GadgetRepo::singleton()->getStructuredList();
                if ( !$gadgets ) {
                        return true;
                }
@@ -71,7 +74,7 @@
         * @return bool
         */
        public static function getPreferences( $user, &$preferences ) {
-               $gadgets = Gadget::loadStructuredList();
+               $gadgets = GadgetRepo::singleton()->getStructuredList();
                if ( !$gadgets ) {
                        return true;
                }
@@ -138,15 +141,14 @@
         * @return bool
         */
        public static function registerModules( &$resourceLoader ) {
-               $gadgets = Gadget::loadList();
-               if ( !$gadgets ) {
+               $repo = GadgetRepo::singleton();
+               $ids = $repo->getGadgetIds();
+               if ( !$ids ) {
                        return true;
                }
 
-               /**
-                * @var $g Gadget
-                */
-               foreach ( $gadgets as $g ) {
+               foreach ( $ids as $id ) {
+                       $g = $repo->getGadget( $id );
                        $module = $g->getModule();
                        if ( $module ) {
                                $resourceLoader->register( $g->getModuleName(), 
$module );
@@ -162,8 +164,9 @@
         * @return bool
         */
        public static function beforePageDisplay( $out ) {
-               $gadgets = Gadget::loadList();
-               if ( !$gadgets ) {
+               $repo = GadgetRepo::singleton();
+               $ids = $repo->getGadgetIds();
+               if ( !$ids ) {
                        return true;
                }
 
@@ -175,7 +178,8 @@
                 * @var $gadget Gadget
                 */
                $user = $out->getUser();
-               foreach ( $gadgets as $gadget ) {
+               foreach ( $ids as $id ) {
+                       $gadget = $repo->getGadget( $id );
                        if ( $gadget->isEnabled( $user ) && $gadget->isAllowed( 
$user ) ) {
                                if ( $gadget->hasModule() ) {
                                        $out->addModuleStyles( 
$gadget->getModuleName() );
@@ -191,7 +195,7 @@
 
                // Allow other extensions, e.g. MobileFrontend, to disallow 
legacy gadgets
                if ( Hooks::run( 'Gadgets::allowLegacy', array( 
$out->getContext() ) ) ) {
-                       $lb->execute( __METHOD__ );
+                       $lb->execute();
 
                        $done = array();
 
diff --git a/Gadgets_body.php b/Gadgets_body.php
index 04c37dc..ebead09 100755
--- a/Gadgets_body.php
+++ b/Gadgets_body.php
@@ -72,76 +72,6 @@
                return strlen( $id ) > 0 && ResourceLoader::isValidModuleName( 
"ext.gadget.$id" );
        }
 
-       /**
-        * Creates an instance of this class from definition in 
MediaWiki:Gadgets-definition
-        * @param $definition String: Gadget definition
-        * @return Gadget|bool Instance of Gadget class or false if $definition 
is invalid
-        */
-       public static function newFromDefinition( $definition ) {
-               $m = array();
-               if ( !preg_match( '/^\*+ *([a-zA-Z](?:[-_:.\w\d 
]*[a-zA-Z0-9])?)(\s*\[.*?\])?\s*((\|[^|]*)+)\s*$/', $definition, $m ) ) {
-                       return false;
-               }
-               // NOTE: the gadget name is used as part of the name of a form 
field,
-               //      and must follow the rules defined in 
http://www.w3.org/TR/html4/types.html#type-cdata
-               //      Also, title-normalization applies.
-               $info = array();
-               $info['name'] = trim( str_replace( ' ', '_', $m[1] ) );
-               // If the name is too long, then RL will throw an MWException 
when
-               // we try to register the module
-               if ( !self::isValidGadgetID( $info['name'] ) ) {
-                       return false;
-               }
-               $info['definition'] = $definition;
-               $options = trim( $m[2], ' []' );
-
-               foreach ( preg_split( '/\s*\|\s*/', $options, -1, 
PREG_SPLIT_NO_EMPTY ) as $option ) {
-                       $arr  = preg_split( '/\s*=\s*/', $option, 2 );
-                       $option = $arr[0];
-                       if ( isset( $arr[1] ) ) {
-                               $params = explode( ',', $arr[1] );
-                               $params = array_map( 'trim', $params );
-                       } else {
-                               $params = array();
-                       }
-
-                       switch ( $option ) {
-                               case 'ResourceLoader':
-                                       $info['resourceLoaded'] = true;
-                                       break;
-                               case 'dependencies':
-                                       $info['dependencies'] = $params;
-                                       break;
-                               case 'rights':
-                                       $info['requiredRights'] = $params;
-                                       break;
-                               case 'skins':
-                                       $info['requiredSkins'] = $params;
-                                       break;
-                               case 'default':
-                                       $info['onByDefault'] = true;
-                                       break;
-                               case 'targets':
-                                       $info['targets'] = $params;
-                                       break;
-                               case 'top':
-                                       $info['position'] = 'top';
-                                       break;
-                       }
-               }
-
-               foreach ( preg_split( '/\s*\|\s*/', $m[3], -1, 
PREG_SPLIT_NO_EMPTY ) as $page ) {
-                       $page = "Gadget-$page";
-
-                       if ( preg_match( '/\.js/', $page ) ) {
-                               $info['scripts'][] = $page;
-                       } elseif ( preg_match( '/\.css/', $page ) ) {
-                               $info['styles'][] = $page;
-                       }
-               }
-
-               return new Gadget( $info );
-       }
 
        /**
         * @return String: Gadget name
@@ -316,168 +246,6 @@
         */
        public function getPosition() {
                return $this->position;
-       }
-
-       /**
-        * Loads and returns a list of all gadgets
-        * @return Mixed: Array of gadgets or false
-        */
-       public static function loadList() {
-               static $gadgets = null;
-
-               if ( $gadgets !== null ) {
-                       return $gadgets;
-               }
-
-               $struct = self::loadStructuredList();
-
-               if ( !$struct ) {
-                       $gadgets = $struct;
-                       return $gadgets;
-               }
-
-               $gadgets = array();
-               foreach ( $struct as $entries ) {
-                       $gadgets = array_merge( $gadgets, $entries );
-               }
-
-               return $gadgets;
-       }
-
-       /**
-        * Loads list of gadgets and returns it as associative array of 
sections with gadgets
-        * e.g. array( 'sectionnname1' => array( $gadget1, $gadget2 ),
-        *             'sectionnname2' => array( $gadget3 ) );
-        * @return array|bool Gadget array or false on failure
-        */
-       public static function loadStructuredList() {
-               if ( self::$definitionCache !== null ) {
-                       return self::$definitionCache; // process cache hit
-               }
-
-               // Ideally $t1Cache is APC, and $wanCache is memcached
-               $t1Cache = ObjectCache::newAccelerator( array(), 'hash' );
-               $wanCache = ObjectCache::getMainWANInstance();
-
-               $key = wfMemcKey( 'gadgets-definition', 
self::GADGET_CLASS_VERSION );
-
-               // (a) Check the tier 1 cache
-               $value = $t1Cache->get( $key );
-               // Check if it passes a blind TTL check (avoids I/O)
-               if ( $value && ( microtime( true ) - $value['time'] ) < 10 ) {
-                       self::$definitionCache = $value['gadgets']; // process 
cache
-                       return self::$definitionCache;
-               }
-               // Cache generated after the "check" time should be up-to-date
-               $ckTime = $wanCache->getCheckKeyTime( $key ) + 
WANObjectCache::HOLDOFF_TTL;
-               if ( $value && $value['time'] > $ckTime ) {
-                       self::$definitionCache = $value['gadgets']; // process 
cache
-                       return self::$definitionCache;
-               }
-
-               // (b) Fetch value from WAN cache or regenerate if needed.
-               // This is hit occasionally and more so when the list changes.
-               $value = $wanCache->getWithSetCallback(
-                       $key,
-                       function( $old, &$ttl ) {
-                               $now = microtime( true );
-                               $gadgets = Gadget::fetchStructuredList();
-                               if ( $gadgets === false ) {
-                                       $ttl = WANObjectCache::TTL_UNCACHEABLE;
-                               }
-
-                               return array( 'gadgets' => $gadgets, 'time' => 
$now );
-                       },
-                       self::CACHE_TTL,
-                       array( $key ),
-                       array( 'lockTSE' => 300 )
-               );
-
-               // Update the tier 1 cache as needed
-               if ( $value['gadgets'] !== false && $value['time'] > $ckTime ) {
-                       // Set a modest TTL to keep the WAN key in cache
-                       $t1Cache->set( $key, $value, mt_rand( 300, 600 ) );
-               }
-
-               self::$definitionCache = $value['gadgets']; // process cache
-
-               return self::$definitionCache;
-       }
-
-       /**
-        * Fetch list of gadgets and returns it as associative array of 
sections with gadgets
-        * e.g. array( 'sectionnname1' => array( $gadget1, $gadget2 ),
-        *             'sectionnname2' => array( $gadget3 ) );
-        * @param $forceNewText String: Injected text of 
MediaWiki:gadgets-definition [optional]
-        * @return array|bool
-        */
-       public static function fetchStructuredList( $forceNewText = null ) {
-               if ( $forceNewText === null ) {
-                       $g = wfMessage( "gadgets-definition" 
)->inContentLanguage();
-                       if ( !$g->exists() ) {
-                               return false; // don't cache
-                       }
-
-                       $g = $g->plain();
-               } else {
-                       $g = $forceNewText;
-               }
-
-               $gadgets = self::listFromDefinition( $g );
-               if ( !count( $gadgets ) ) {
-                       return false; // don't cache; Bug 37228
-               }
-
-               $source = $forceNewText !== null ? 'input text' : 
'MediaWiki:Gadgets-definition';
-               wfDebug( __METHOD__ . ": $source parsed, cache entry should be 
updated\n" );
-
-               return $gadgets;
-       }
-
-       /**
-        * Generates a structured list of Gadget objects from a definition
-        *
-        * @param $definition
-        * @return array Array( category => Array( name => Gadget ) )
-        */
-       private static function listFromDefinition( $definition ) {
-               $definition = preg_replace( '/<!--.*?-->/s', '', $definition );
-               $lines = preg_split( '/(\r\n|\r|\n)+/', $definition );
-
-               $gadgets = array();
-               $section = '';
-
-               foreach ( $lines as $line ) {
-                       $m = array();
-                       if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', 
$line, $m ) ) {
-                               $section = $m[1];
-                       } else {
-                               $gadget = self::newFromDefinition( $line );
-                               if ( $gadget ) {
-                                       $gadgets[$section][$gadget->getName()] 
= $gadget;
-                                       $gadget->category = $section;
-                               }
-                       }
-               }
-
-               return $gadgets;
-       }
-
-       /**
-        * Update MediaWiki:Gadgets-definition cache
-        */
-       public static function purgeDefinitionCache() {
-               $key = wfMemcKey( 'gadgets-definition', 
Gadget::GADGET_CLASS_VERSION );
-               ObjectCache::getMainWANInstance()->touchCheckKey( $key );
-       }
-
-       /**
-        * Inject gadgets into the process cache for unit tests
-        *
-        * @param array|bool $cache Result of fetchStructuredList()
-        */
-       public static function injectDefinitionCache( $cache ) {
-               self::$definitionCache = $cache;
        }
 }
 
diff --git a/SpecialGadgets.php b/SpecialGadgets.php
index 22b6ca2..aa16afa 100644
--- a/SpecialGadgets.php
+++ b/SpecialGadgets.php
@@ -39,7 +39,7 @@
                $output->setPagetitle( $this->msg( 'gadgets-title' ) );
                $output->addWikiMsg( 'gadgets-pagetext' );
 
-               $gadgets = Gadget::loadStructuredList();
+               $gadgets = GadgetRepo::singleton()->getStructuredList();
                if ( !$gadgets ) {
                        return;
                }
@@ -171,16 +171,13 @@
                global $wgScript;
 
                $output = $this->getOutput();
-               $gadgets = Gadget::loadList();
-               if ( !isset( $gadgets[$gadget] ) ) {
+               try {
+                       $g = GadgetRepo::singleton()->getGadget( $gadget );
+               } catch ( InvalidArgumentException $e ) {
                        $output->showErrorPage( 'error', 'gadgets-not-found', 
array( $gadget ) );
                        return;
                }
 
-               /**
-                * @var $g Gadget
-                */
-               $g = $gadgets[$gadget];
                $this->setHeaders();
                $output->setPagetitle( $this->msg( 'gadgets-export-title' ) );
                $output->addWikiMsg( 'gadgets-export-text', $gadget, 
$g->getDefinition() );
diff --git a/api/ApiQueryGadgetCategories.php b/api/ApiQueryGadgetCategories.php
index eb29ceb..8bfd6c0 100644
--- a/api/ApiQueryGadgetCategories.php
+++ b/api/ApiQueryGadgetCategories.php
@@ -49,7 +49,7 @@
        private function getList() {
                $data = array();
                $result = $this->getResult();
-               $gadgets = Gadget::loadStructuredList();
+               $gadgets = GadgetRepo::singleton()->getStructuredList();
 
                if ( $gadgets ) {
                        foreach ( $gadgets as $category => $list ) {
diff --git a/api/ApiQueryGadgets.php b/api/ApiQueryGadgets.php
index 8bd02b9..57fdb14 100644
--- a/api/ApiQueryGadgets.php
+++ b/api/ApiQueryGadgets.php
@@ -71,7 +71,7 @@
         * @return array
         */
        private function getList() {
-               $gadgets = Gadget::loadStructuredList();
+               $gadgets = GadgetRepo::singleton()->getStructuredList();
 
                if ( $gadgets === false ) {
                        return array();
diff --git a/extension.json b/extension.json
index 708b6f4..ca1258f 100755
--- a/extension.json
+++ b/extension.json
@@ -29,7 +29,9 @@
                "Gadget": "Gadgets_body.php",
                "GadgetHooks": "GadgetHooks.php",
                "GadgetResourceLoaderModule": "Gadgets_body.php",
-               "SpecialGadgets": "SpecialGadgets.php"
+               "SpecialGadgets": "SpecialGadgets.php",
+               "GadgetRepo": "includes/GadgetRepo.php",
+               "MediaWikiGadgetsDefinitionRepo": 
"includes/MediaWikiGadgetsDefinitionRepo.php"
        },
        "Hooks": {
                "ArticleSaveComplete": [
diff --git a/includes/GadgetRepo.php b/includes/GadgetRepo.php
new file mode 100644
index 0000000..18bf5b5
--- /dev/null
+++ b/includes/GadgetRepo.php
@@ -0,0 +1,63 @@
+<?php
+
+abstract class GadgetRepo {
+
+       /**
+        * @var GadgetRepo|null
+        */
+       private static $instance;
+
+       /**
+        * Get the ids of the gadgets provided by this repository
+        *
+        * @return string[]
+        */
+       abstract public function getGadgetIds();
+
+       /**
+        * Get the Gadget object for a given gadget id
+        *
+        * @param string $id
+        * @throws InvalidArgumentException
+        * @return Gadget
+        */
+       abstract public function getGadget( $id );
+
+       /**
+        * Get a list of gadgets sorted by category
+        *
+        * @return array array( 'category' => array( 'name' => $gadget ) )
+        */
+       public function getStructuredList() {
+               $list = array();
+               foreach ( $this->getGadgetIds() as $id ) {
+                       $gadget = $this->getGadget( $id );
+                       $list[$gadget->getCategory()][$gadget->getName()] = 
$gadget;
+               }
+
+               return $list;
+       }
+
+       /**
+        * Get the configured default GadgetRepo. Currently
+        * this hardcodes MediaWikiGadgetsDefinitionRepo since
+        * that is the only implementation
+        *
+        * @return GadgetRepo
+        */
+       public static function singleton() {
+               if ( self::$instance === null ) {
+                       self::$instance = new MediaWikiGadgetsDefinitionRepo();
+               }
+               return self::$instance;
+       }
+
+       /**
+        * Should only be used by unit tests
+        *
+        * @param GadgetRepo|null $repo
+        */
+       public static function setSingleton( $repo = null ) {
+               self::$instance = $repo;
+       }
+}
diff --git a/includes/MediaWikiGadgetsDefinitionRepo.php 
b/includes/MediaWikiGadgetsDefinitionRepo.php
new file mode 100644
index 0000000..eb141a9
--- /dev/null
+++ b/includes/MediaWikiGadgetsDefinitionRepo.php
@@ -0,0 +1,233 @@
+<?php
+
+/**
+ * Gadgets repo powered by MediaWiki:Gadgets-definition
+ */
+class MediaWikiGadgetsDefinitionRepo extends GadgetRepo {
+
+       const CACHE_VERSION = 1;
+
+       private $definitionCache;
+
+       public function getGadget( $id ) {
+               $gadgets = $this->loadGadgets();
+               if ( !isset( $gadgets[$id] ) ) {
+                       throw new InvalidArgumentException( "No gadget 
registered for '$id'" );
+               }
+
+               return $gadgets[$id];
+       }
+
+       public function getGadgetIds() {
+               $gadgets = $this->loadGadgets();
+               if ( $gadgets ) {
+                       return array_keys( $gadgets );
+               } else {
+                       return array();
+               }
+       }
+
+       /**
+        * Purge the definitions cache, for example if 
MediaWiki:Gadgets-definition
+        * was edited.
+        */
+       public function purgeDefinitionCache() {
+               ObjectCache::getMainWANInstance()->touchCheckKey( 
$this->getCheckKey() );
+       }
+
+       private function getCheckKey() {
+               return wfMemcKey( 'gadgets-definition', 
Gadget::GADGET_CLASS_VERSION, self::CACHE_VERSION );
+       }
+
+       /**
+        * Loads list of gadgets and returns it as associative array of 
sections with gadgets
+        * e.g. array( 'sectionnname1' => array( $gadget1, $gadget2 ),
+        *             'sectionnname2' => array( $gadget3 ) );
+        * @return array|bool Gadget array or false on failure
+        */
+       protected function loadGadgets() {
+               if ( $this->definitionCache !== null ) {
+                       return $this->definitionCache; // process cache hit
+               }
+
+               // Ideally $t1Cache is APC, and $wanCache is memcached
+               $t1Cache = ObjectCache::newAccelerator( array(), 'hash' );
+               $wanCache = ObjectCache::getMainWANInstance();
+
+               $key = $this->getCheckKey();
+
+               // (a) Check the tier 1 cache
+               $value = $t1Cache->get( $key );
+               // Check if it passes a blind TTL check (avoids I/O)
+               if ( $value && ( microtime( true ) - $value['time'] ) < 10 ) {
+                       $this->definitionCache = $value['gadgets']; // process 
cache
+                       return $this->definitionCache;
+               }
+               // Cache generated after the "check" time should be up-to-date
+               $ckTime = $wanCache->getCheckKeyTime( $key ) + 
WANObjectCache::HOLDOFF_TTL;
+               if ( $value && $value['time'] > $ckTime ) {
+                       $this->definitionCache = $value['gadgets']; // process 
cache
+                       return $this->definitionCache;
+               }
+
+               // (b) Fetch value from WAN cache or regenerate if needed.
+               // This is hit occasionally and more so when the list changes.
+               $us = $this;
+               $value = $wanCache->getWithSetCallback(
+                       $key,
+                       function( $old, &$ttl ) use ( $us ) {
+                               $now = microtime( true );
+                               $gadgets = $us->fetchStructuredList();
+                               if ( $gadgets === false ) {
+                                       $ttl = WANObjectCache::TTL_UNCACHEABLE;
+                               }
+
+                               return array( 'gadgets' => $gadgets, 'time' => 
$now );
+                       },
+                       Gadget::CACHE_TTL,
+                       array( $key ),
+                       array( 'lockTSE' => 300 )
+               );
+
+               // Update the tier 1 cache as needed
+               if ( $value['gadgets'] !== false && $value['time'] > $ckTime ) {
+                       // Set a modest TTL to keep the WAN key in cache
+                       $t1Cache->set( $key, $value, mt_rand( 300, 600 ) );
+               }
+
+               $this->definitionCache = $value['gadgets'];
+
+               return $this->definitionCache;
+       }
+
+       /**
+        * Fetch list of gadgets and returns it as associative array of 
sections with gadgets
+        * e.g. array( $name => $gadget1, etc. )
+        * @param $forceNewText String: Injected text of 
MediaWiki:gadgets-definition [optional]
+        * @return array|bool
+        */
+       public function fetchStructuredList( $forceNewText = null ) {
+               if ( $forceNewText === null ) {
+                       $g = wfMessage( "gadgets-definition" 
)->inContentLanguage();
+                       if ( !$g->exists() ) {
+                               return false; // don't cache
+                       }
+
+                       $g = $g->plain();
+               } else {
+                       $g = $forceNewText;
+               }
+
+               $gadgets = $this->listFromDefinition( $g );
+               if ( !count( $gadgets ) ) {
+                       return false; // don't cache; Bug 37228
+               }
+
+               $source = $forceNewText !== null ? 'input text' : 
'MediaWiki:Gadgets-definition';
+               wfDebug( __METHOD__ . ": $source parsed, cache entry should be 
updated\n" );
+
+               return $gadgets;
+       }
+
+       /**
+        * Generates a structured list of Gadget objects from a definition
+        *
+        * @param $definition
+        * @return array Array( name => Gadget )
+        */
+       private function listFromDefinition( $definition ) {
+               $definition = preg_replace( '/<!--.*?-->/s', '', $definition );
+               $lines = preg_split( '/(\r\n|\r|\n)+/', $definition );
+
+               $gadgets = array();
+               $section = '';
+
+               foreach ( $lines as $line ) {
+                       $m = array();
+                       if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', 
$line, $m ) ) {
+                               $section = $m[1];
+                       } else {
+                               $gadget = $this->newFromDefinition( $line, 
$section );
+                               if ( $gadget ) {
+                                       $gadgets[$gadget->getName()] = $gadget;
+                               }
+                       }
+               }
+
+               return $gadgets;
+       }
+
+       /**
+        * Creates an instance of this class from definition in 
MediaWiki:Gadgets-definition
+        * @param string $definition Gadget definition
+        * @param string $category
+        * @return Gadget|bool Instance of Gadget class or false if $definition 
is invalid
+        */
+       public function newFromDefinition( $definition, $category ) {
+               $m = array();
+               if ( !preg_match( '/^\*+ *([a-zA-Z](?:[-_:.\w\d 
]*[a-zA-Z0-9])?)(\s*\[.*?\])?\s*((\|[^|]*)+)\s*$/', $definition, $m ) ) {
+                       return false;
+               }
+               // NOTE: the gadget name is used as part of the name of a form 
field,
+               //      and must follow the rules defined in 
http://www.w3.org/TR/html4/types.html#type-cdata
+               //      Also, title-normalization applies.
+               $info = array( 'category' => $category );
+               $info['name'] = trim( str_replace( ' ', '_', $m[1] ) );
+               // If the name is too long, then RL will throw an MWException 
when
+               // we try to register the module
+               if ( !Gadget::isValidGadgetID( $info['name'] ) ) {
+                       return false;
+               }
+               $info['definition'] = $definition;
+               $options = trim( $m[2], ' []' );
+
+               foreach ( preg_split( '/\s*\|\s*/', $options, -1, 
PREG_SPLIT_NO_EMPTY ) as $option ) {
+                       $arr  = preg_split( '/\s*=\s*/', $option, 2 );
+                       $option = $arr[0];
+                       if ( isset( $arr[1] ) ) {
+                               $params = explode( ',', $arr[1] );
+                               $params = array_map( 'trim', $params );
+                       } else {
+                               $params = array();
+                       }
+
+                       switch ( $option ) {
+                               case 'ResourceLoader':
+                                       $info['resourceLoaded'] = true;
+                                       break;
+                               case 'dependencies':
+                                       $info['dependencies'] = $params;
+                                       break;
+                               case 'rights':
+                                       $info['requiredRights'] = $params;
+                                       break;
+                               case 'skins':
+                                       $info['requiredSkins'] = $params;
+                                       break;
+                               case 'default':
+                                       $info['onByDefault'] = true;
+                                       break;
+                               case 'targets':
+                                       $info['targets'] = $params;
+                                       break;
+                               case 'top':
+                                       $info['position'] = 'top';
+                                       break;
+                       }
+               }
+
+               foreach ( preg_split( '/\s*\|\s*/', $m[3], -1, 
PREG_SPLIT_NO_EMPTY ) as $page ) {
+                       $page = "Gadget-$page";
+
+                       if ( preg_match( '/\.js/', $page ) ) {
+                               $info['scripts'][] = $page;
+                       } elseif ( preg_match( '/\.css/', $page ) ) {
+                               $info['styles'][] = $page;
+                       }
+               }
+
+               return new Gadget( $info );
+       }
+
+
+}
diff --git a/tests/GadgetTest.php b/tests/GadgetTest.php
index 65f2966..26d77e5 100644
--- a/tests/GadgetTest.php
+++ b/tests/GadgetTest.php
@@ -4,16 +4,22 @@
  */
 
 class GadgetsTest extends MediaWikiTestCase {
+       /**
+        * @param string $line
+        * @return Gadget
+        */
        private function create( $line ) {
-               $g = Gadget::newFromDefinition( $line );
+               $repo = new MediaWikiGadgetsDefinitionRepo();
+               $g = $repo->newFromDefinition( $line, 'misc' );
                $this->assertInstanceOf( 'Gadget', $g );
 
                return $g;
        }
 
        public function testInvalidLines() {
-               $this->assertFalse( Gadget::newFromDefinition( '' ) );
-               $this->assertFalse( Gadget::newFromDefinition( '<foo|bar>' ) );
+               $repo = new MediaWikiGadgetsDefinitionRepo();
+               $this->assertFalse( $repo->newFromDefinition( '', 'misc' ) );
+               $this->assertFalse( $repo->newFromDefinition( '<foo|bar>', 
'misc' ) );
        }
 
        public function testSimpleCases() {
@@ -45,8 +51,11 @@
 
        public function testPreferences() {
                $prefs = array();
+               $repo = TestingAccessWrapper::newFromObject( new 
MediaWikiGadgetsDefinitionRepo() );
+               // Force usage of a MediaWikiGadgetsDefinitionRepo
+               GadgetRepo::setSingleton( $repo );
 
-               $gadgets = Gadget::fetchStructuredList( '* foo | foo.js
+               $gadgets = $repo->fetchStructuredList( '* foo | foo.js
 ==keep-section1==
 * bar| bar.js
 ==remove-section==
@@ -55,7 +64,7 @@
 * quux [rights=read] | quux.js' );
                $this->assertGreaterThanOrEqual( 2, count( $gadgets ), "Gadget 
list parsed" );
 
-               Gadget::injectDefinitionCache( $gadgets );
+               $repo->definitionCache = $gadgets;
                $this->assertTrue( GadgetHooks::getPreferences( new User, 
$prefs ), 'GetPrefences hook should return true' );
 
                $options = $prefs['gadgets']['options'];
@@ -63,4 +72,9 @@
                $this->assertTrue( isset( 
$options['&lt;gadget-section-keep-section1&gt;'] ) );
                $this->assertTrue( isset( 
$options['&lt;gadget-section-keep-section2&gt;'] ) );
        }
+
+       public function tearDown() {
+               GadgetRepo::setSingleton();
+               parent::tearDown();
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/225659
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I3e802889f6f495783f4dbac65c2a8cefa824a778
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/Gadgets
Gerrit-Branch: master
Gerrit-Owner: Legoktm <[email protected]>
Gerrit-Reviewer: Alex Monk <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to