Physikerwelt has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/275706

Change subject: WIP: contentMathMLdatatype
......................................................................

WIP: contentMathMLdatatype

Change-Id: Iaf55d30a84df9349f3ee6e0b13709c7412af1945
---
A ContentMathFormatter.php
A ContentMathMLRdfBuilder.php
A ContentMathValidator.php
A ContentMathWikidataHook.php
M extension.json
A tests/ContentMathFormatterTest.php
A tests/ContentMathMLRdfBuilderTest.php
A tests/ContentMathValidatorTest.php
8 files changed, 479 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MathSearch 
refs/changes/06/275706/1

diff --git a/ContentMathFormatter.php b/ContentMathFormatter.php
new file mode 100644
index 0000000..9c56897
--- /dev/null
+++ b/ContentMathFormatter.php
@@ -0,0 +1,111 @@
+<?php
+
+use DataValues\StringValue;
+use ValueFormatters\Exceptions\MismatchingDataValueTypeException;
+use ValueFormatters\ValueFormatter;
+use Wikibase\Lib\SnakFormatter;
+
+/*
+* Formats the tex string based on the known formats
+* * text/plain: used in the value input field of Wikidata
+* * text/x-wiki: wikitext
+* * text/html: used in Wikidata to display the value of properties
+* Formats can look like this: "text/html; disposition=widget"
+* or just "text/plain"
+*/
+
+class ContentMathFormatter implements ValueFormatter {
+
+       /**
+        * @var string One of the SnakFormatter::FORMAT_... constants.
+        */
+       private $format;
+
+       /**
+        * Loads format to distinguish the type of formatting
+        *
+        * @param string $format One of the SnakFormatter::FORMAT_... constants.
+        *
+        * @throws InvalidArgumentException
+        */
+       public function __construct( $format ) {
+               switch ( $format ) {
+                       case SnakFormatter::FORMAT_PLAIN:
+                       case SnakFormatter::FORMAT_WIKI:
+                       case SnakFormatter::FORMAT_HTML:
+                       case SnakFormatter::FORMAT_HTML_DIFF:
+                       case SnakFormatter::FORMAT_HTML_WIDGET:
+                               $this->format = $format;
+                               break;
+                       default:
+                               throw new InvalidArgumentException( 
'Unsupported output format: ' . $format );
+               }
+       }
+
+       /**
+        * @param StringValue $value
+        *
+        * @throws MismatchingDataValueTypeException
+        * @return string
+        */
+       public function format( $value ) {
+               if ( !( $value instanceof StringValue ) ) {
+                       throw new MismatchingDataValueTypeException( 
'StringValue', get_class( $value ) );
+               }
+
+               $tex = $value->getValue();
+
+               switch ( $this->format ) {
+                       case SnakFormatter::FORMAT_PLAIN:
+                               return $tex;
+                       case SnakFormatter::FORMAT_WIKI:
+                               return "<math>$tex</math>";
+                       default:
+                               $renderer = new MathLaTeXML( $tex );
+
+                               if ( $renderer->checkTex() && 
$renderer->render() ) {
+                                       $html = $renderer->getHtmlOutput();
+                               } else {
+                                       $html = $renderer->getLastError();
+                               }
+
+                               if ( $this->format === 
SnakFormatter::FORMAT_HTML_DIFF ) {
+                                       $html = $this->formatDetails( $html, 
$tex );
+                               }
+
+                               // TeX string is not valid or rendering failed
+                               return $html;
+               }
+       }
+
+       /**
+        * Constructs a detailed HTML rendering for use in diff views.
+        *
+        * @param string $valueHtml HTML
+        * @param string $tex TeX
+        *
+        * @return string HTML
+        */
+       private function formatDetails( $valueHtml, $tex ) {
+               $html = '';
+               $html .= Html::rawElement( 'h4',
+                       array( 'class' => 'wb-details wb-math-details 
wb-math-rendered' ),
+                       $valueHtml
+               );
+
+               $html .= Html::rawElement( 'div',
+                       array( 'class' => 'wb-details wb-math-details' ),
+                       Html::element( 'code', array(), $tex )
+               );
+
+               return $html;
+       }
+
+       /**
+        * @return string One of the SnakFormatter::FORMAT_... constants.
+        */
+       public function getFormat() {
+               return $this->format;
+       }
+
+}
diff --git a/ContentMathMLRdfBuilder.php b/ContentMathMLRdfBuilder.php
new file mode 100644
index 0000000..8e8cb30
--- /dev/null
+++ b/ContentMathMLRdfBuilder.php
@@ -0,0 +1,35 @@
+<?php
+
+use Wikibase\DataModel\Snak\PropertyValueSnak;
+use Wikibase\Rdf\ValueSnakRdfBuilder;
+use Wikimedia\Purtle\RdfWriter;
+
+class ContentMathMLRdfBuilder implements ValueSnakRdfBuilder {
+
+       /**
+        * Adds a value
+        *
+        * @param RdfWriter $writer
+        * @param string $propertyValueNamespace Property value relation 
namespace
+        * @param string $propertyValueLName Property value relation name
+        * @param string $dataType Property data type
+        * @param PropertyValueSnak $snak
+        */
+       public function addValue(
+               RdfWriter $writer,
+               $propertyValueNamespace,
+               $propertyValueLName,
+               $dataType,
+               PropertyValueSnak $snak
+       ) {
+               $renderer = new MathLaTeXML( $snak->getDataValue()->getValue() 
);
+               if ( $renderer->checkTeX() && $renderer->render() ) {
+                       $mml = $renderer->getMathml();
+               } else {
+                       $err = $renderer->getLastError();
+                       $mml = "<math 
xmlns=\"http://www.w3.org/1998/Math/MathML\";><merror>$err</merror></math>";
+               }
+               $writer->say( $propertyValueNamespace, $propertyValueLName )
+                       ->value( $mml, 'http://www.w3.org/1998/Math/MathML' );
+       }
+}
diff --git a/ContentMathValidator.php b/ContentMathValidator.php
new file mode 100644
index 0000000..3d71708
--- /dev/null
+++ b/ContentMathValidator.php
@@ -0,0 +1,50 @@
+<?php
+
+use ValueFormatters\Exceptions\MismatchingDataValueTypeException;
+use ValueValidators\Result;
+use ValueValidators\ValueValidator;
+use ValueValidators\Error;
+use DataValues\StringValue;
+
+// @author Duc Linh Tran, Julian Hilbig, Moritz Schubotz
+
+class ContentMathValidator implements ValueValidator {
+
+       /**
+        * Validates a value with MathLaTeXML
+        *
+        * @param mixed $value The value to validate
+        *
+        * @return \ValueValidators\Result
+        * @throws ValueFormatters\Exceptions\MismatchingDataValueTypeException
+        */
+       public function validate( $value ) {
+               if ( !( $value instanceof StringValue ) ) {
+                       throw new MismatchingDataValueTypeException( 
'StringValue', get_class( $value ) );
+               }
+
+               // get input String from value
+               $tex = $value->getValue();
+
+               $checker = new MathLaTeXML( $tex );
+               if ( $checker->checkTeX() )  {
+                       return Result::newSuccess();
+               }
+
+               // TeX string is not valid
+               return Result::newError(
+                       array(
+                               Error::newError( null, null, 'malformed-value', 
array( $checker->getLastError() ) )
+                       )
+               );
+       }
+
+       /**
+        * @see ValueValidator::setOptions()
+        *
+        * @param array $options
+        */
+       public function setOptions( array $options ) {
+               // Do nothing. This method shouldn't even be in the interface.
+       }
+}
diff --git a/ContentMathWikidataHook.php b/ContentMathWikidataHook.php
new file mode 100644
index 0000000..bba06a1
--- /dev/null
+++ b/ContentMathWikidataHook.php
@@ -0,0 +1,81 @@
+<?php
+
+use ValueFormatters\FormatterOptions;
+use ValueParsers\StringParser;
+use Wikibase\Rdf\DedupeBag;
+use Wikibase\Rdf\EntityMentionListener;
+use Wikibase\Rdf\RdfVocabulary;
+use Wikibase\Repo\Parsers\WikibaseStringValueNormalizer;
+use Wikibase\Repo\WikibaseRepo;
+use Wikimedia\Purtle\RdfWriter;
+
+class ContentMathWikidataHook {
+
+       /**
+        * Add Datatype "ContentMath" to the Wikibase Repository
+        */
+       public static function onWikibaseRepoDataTypes( array 
&$dataTypeDefinitions ) {
+               global $wgContentMathEnableWikibaseDataType;
+
+               if ( !$wgContentMathEnableWikibaseDataType ) {
+                       return;
+               }
+
+               $dataTypeDefinitions['PT:contentMath'] = array(
+                       'value-type'                 => 'string',
+                       'validator-factory-callback' => function() {
+                               // load validator builders
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+
+                               // initialize an array with string validators
+                               // returns an array of validators
+                               // that add basic string validation such as 
preventing empty strings
+                               $validators = $factory->buildStringValidators();
+                               $validators[] = new ContentMathValidator();
+                               return $validators;
+                       },
+                       'parser-factory-callback' => function( ParserOptions 
$options ) {
+                               $repo = WikibaseRepo::getDefaultInstance();
+                               $normalizer = new 
WikibaseStringValueNormalizer( $repo->getStringNormalizer() );
+                               return new StringParser( $normalizer );
+                       },
+                       'formatter-factory-callback' => function( $format, 
FormatterOptions $options ) {
+                               global $wgOut;
+                               $styles = array( 'ext.math.desktop.styles', 
'ext.math.scripts', 'ext.math.styles' );
+                               $wgOut->addModuleStyles( $styles );
+                               return new ContentMathFormatter( $format );
+                       },
+                       'rdf-builder-factory-callback' => function (
+                               $mode,
+                               RdfVocabulary $vocab,
+                               RdfWriter $writer,
+                               EntityMentionListener $tracker,
+                               DedupeBag $dedupe
+                       ) {
+                               return new ContentMathMLRdfBuilder();
+                       },
+               );
+       }
+
+       /*
+        * Add Datatype "ContentMath" to the Wikibase Client
+        */
+       public static function onWikibaseClientDataTypes( array 
&$dataTypeDefinitions ) {
+               global $wgContentMathEnableWikibaseDataType;
+
+               if ( !$wgContentMathEnableWikibaseDataType ) {
+                       return;
+               }
+
+               $dataTypeDefinitions['PT:contentmath'] = array(
+                       'value-type'                 => 'string',
+                       'formatter-factory-callback' => function( $format, 
FormatterOptions $options ) {
+                               global $wgOut;
+                               $styles = array( 'ext.math.desktop.styles', 
'ext.math.scripts', 'ext.math.styles' );
+                               $wgOut->addModuleStyles( $styles );
+                               return new ContentMathFormatter( $format );
+                       },
+               );
+       }
+
+}
diff --git a/extension.json b/extension.json
index 44a8076..ee452c9 100644
--- a/extension.json
+++ b/extension.json
@@ -34,7 +34,11 @@
                "MathIdGenerator": "includes/MathIdGenerator.php",
                "MathHighlighter": "includes/MathHighlighter.php",
                "MlpEvalForm": "includes/MlpEvalForm.php",
-               "WikidataDriver": "includes/WikidataDriver.php"
+               "WikidataDriver": "includes/WikidataDriver.php",
+               "ContentMathValidator": "ContentMathValidator.php",
+               "ContentMathFormatter": "ContentMathFormatter.php",
+               "ContentMathWikidataHook": "ContentMathWikidataHook.php",
+               "ContentMathMLRdfBuilder": "ContentMathMLRdfBuilder.php"
        },
        "AvailableRights": [
                "mathwmcsubmit"
diff --git a/tests/ContentMathFormatterTest.php 
b/tests/ContentMathFormatterTest.php
new file mode 100644
index 0000000..288e531
--- /dev/null
+++ b/tests/ContentMathFormatterTest.php
@@ -0,0 +1,90 @@
+<?php
+
+use DataValues\StringValue;
+use DataValues\NumberValue;
+use Wikibase\Lib\SnakFormatter;
+
+/**
+ * Test the results of MathFormatter
+ *
+ * @covers MathFormatter
+ *
+ * @group MathSearch
+ *
+ * @licence GNU GPL v2+
+ */
+class ContentMathFormatterTest extends MediaWikiTestCase {
+
+       const SOME_TEX = 'a^2+b^2 < c^2';
+
+       /**
+        * Checks the
+        * @covers MathFormatter::__construct()
+        */
+       public function testBasics() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_PLAIN );
+               // check if the format input was corretly passed to the class
+               $this->assertSame( SnakFormatter::FORMAT_PLAIN, 
$formatter->getFormat(), 'test getFormat' );
+       }
+
+       /**
+        * @expectedException 
ValueFormatters\Exceptions\MismatchingDataValueTypeException
+        */
+       public function testNotStringValue() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_PLAIN );
+               $formatter->format( new NumberValue( 0 ) );
+       }
+
+       /**
+        * @expectedException 
ValueFormatters\Exceptions\MismatchingDataValueTypeException
+        */
+       public function testNullValue() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_PLAIN );
+               $formatter->format( null );
+       }
+
+       /**
+        * @expectedException InvalidArgumentException
+        */
+       public function testUnknownFormat() {
+               new ContentMathFormatter( 'unknown/unknown' );
+       }
+
+       public function testFormatPlain() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_PLAIN );
+               $value = new StringValue( self::SOME_TEX );
+               $resultFormat = $formatter->format( $value );
+               $this->assertSame( self::SOME_TEX, $resultFormat );
+       }
+
+       public function testFormatHtml() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_HTML );
+               $value = new StringValue( self::SOME_TEX );
+               $resultFormat = $formatter->format( $value );
+               $this->assertContains( '</math>', $resultFormat, 'Result must 
contain math-tag' );
+       }
+
+       public function testFormatDiffHtml() {
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_HTML_DIFF );
+               $value = new StringValue( self::SOME_TEX );
+               $resultFormat = $formatter->format( $value );
+               $this->assertContains( '</math>', $resultFormat, 'Result must 
contain math-tag' );
+               $this->assertContains( '</h4>', $resultFormat, 'Result must 
contain a <h4> tag' );
+               $this->assertContains( '</code>', $resultFormat, 'Result must 
contain a <code> tag' );
+               $this->assertContains( 'wb-details', $resultFormat, 'Result 
must contain wb-details class' );
+               $this->assertContains(
+                       htmlspecialchars( self::SOME_TEX ),
+                       $resultFormat,
+                       'Result must contain the TeX source'
+               );
+       }
+
+       public function testFormatXWiki() {
+               $tex = self::SOME_TEX;
+               $formatter = new ContentMathFormatter( 
SnakFormatter::FORMAT_WIKI );
+               $value = new StringValue( self::SOME_TEX );
+               $resultFormat = $formatter->format( $value );
+               $this->assertSame( "<math>$tex</math>", $resultFormat, 'Tex 
wasn\'t properly wrapped' );
+       }
+
+}
diff --git a/tests/ContentMathMLRdfBuilderTest.php 
b/tests/ContentMathMLRdfBuilderTest.php
new file mode 100644
index 0000000..ab6db6a
--- /dev/null
+++ b/tests/ContentMathMLRdfBuilderTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Test the ContentMathML RDF formatter
+ *
+ * @group ContentMath
+ * @covers ContentMathMLRdfBuilder
+ * @author Moritz Schubotz (physikerwelt)
+ */
+
+use DataValues\StringValue;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\DataModel\Snak\PropertyValueSnak;
+use Wikimedia\Purtle\NTriplesRdfWriter;
+
+class ContentMathMLRdfBuilderTest extends MediaWikiTestCase {
+       const ACME_PREFIX_URL = 'http://acme/';
+       const ACME_REF = 'testing';
+
+       /**
+        *
+        * @param string $test
+        * @return string
+        */
+       private function makeCase( $test ) {
+               $builder = new ContentMathMLRdfBuilder();
+               $writer = new NTriplesRdfWriter();
+               $writer->prefix( 'www', "http://www/"; );
+               $writer->prefix( 'acme', self::ACME_PREFIX_URL );
+
+               $writer->start();
+               $writer->about( 'www', 'Q1' );
+
+               $snak = new PropertyValueSnak( new PropertyId( 'P1' ), new 
StringValue( $test ) );
+               $builder->addValue( $writer, 'acme', self::ACME_REF, 'DUMMY', 
$snak );
+
+               return trim( $writer->drain() );
+       }
+
+       public function testValidInput() {
+               $triples = $this->makeCase( 'a^2' );
+               $this->assertContains( self::ACME_PREFIX_URL . self::ACME_REF . 
'> "<math', $triples );
+               $this->assertContains( '>a</mi>\n', $triples );
+               $this->assertContains( '>2</mn>\n', $triples );
+               $this->assertContains( 'a^{2}', $triples );
+               $this->assertContains( '^^<http://www.w3.org/1998/Math/MathML> 
.', $triples );
+       }
+
+       public function testInvalidInput() {
+               $triples = $this->makeCase( '\notExists' );
+               $this->assertContains( '<math', $triples );
+               $this->assertContains( 'undefined undefined', $triples );
+               $this->assertContains( 'notExists', $triples );
+               $this->assertContains( '^^<http://www.w3.org/1998/Math/MathML> 
.', $triples );
+       }
+}
diff --git a/tests/ContentMathValidatorTest.php 
b/tests/ContentMathValidatorTest.php
new file mode 100644
index 0000000..c743fe8
--- /dev/null
+++ b/tests/ContentMathValidatorTest.php
@@ -0,0 +1,52 @@
+<?php
+
+use DataValues\StringValue;
+use DataValues\NumberValue;
+
+/**
+ * @covers MathValidator
+ *
+ * @group ContentContentMath
+ *
+ * @licence GNU GPL v2+
+ */
+class ContentMathValidatorTest extends MediaWikiTestCase {
+       const VADLID_TEX = "a^2+b^2=c^2";
+       const INVADLID_TEX = "\\notExists";
+
+       protected function tearDown() {
+               parent::tearDown();
+       }
+
+       /**
+        * @expectedException 
ValueFormatters\Exceptions\MismatchingDataValueTypeException
+        */
+       public function testNotStringValue() {
+               $validator = new ContentMathValidator();
+               $validator->validate( new NumberValue( 0 ) );
+       }
+
+       /**
+        * @expectedException 
ValueFormatters\Exceptions\MismatchingDataValueTypeException
+        */
+       public function testNullValue() {
+               $validator = new ContentMathValidator();
+               $validator->validate( null );
+       }
+
+       public function testValidInput() {
+               $validator = new ContentMathValidator();
+               $result = $validator->validate( new StringValue( 
self::VADLID_TEX ) );
+               // not supported by jenkins php version
+               // $this->assertType( \ValueValidators\Result::class, $result );
+               $this->assertTrue( $result->isValid() );
+       }
+
+       public function testInvalidInput() {
+               $validator = new ContentMathValidator();
+               $result = $validator->validate( new StringValue( 
self::INVADLID_TEX ) );
+               // not supported by jenkins php version
+               // $this->assertType( \ValueValidators\Result::class, $result );
+               $this->assertFalse( $result->isValid() );
+       }
+}

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaf55d30a84df9349f3ee6e0b13709c7412af1945
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MathSearch
Gerrit-Branch: master
Gerrit-Owner: Physikerwelt <[email protected]>

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

Reply via email to