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