Merge branch '2.3' into 2.7

* 2.3:
  [Yaml] fix exception contexts
  People - person singularization
  [Yaml] properly handle unindented collections
  chomp newlines only at the end of YAML documents
This commit is contained in:
Fabien Potencier 2016-05-24 11:57:18 +02:00
commit eac5868d20
4 changed files with 61 additions and 13 deletions

View File

@ -124,6 +124,9 @@ class StringUtil
// chateaux (chateau)
array('xuae', 4, false, true, 'eau'),
// people (person)
array('elpoep', 6, true, true, 'person'),
);
/**

View File

@ -107,6 +107,8 @@ class StringUtilTest extends \PHPUnit_Framework_TestCase
array('objectives', 'objective'),
array('oxen', 'ox'),
array('parties', 'party'),
array('people', 'person'),
array('persons', 'person'),
array('phenomena', array('phenomenon', 'phenomenum')),
array('photos', 'photo'),
array('pianos', 'piano'),

View File

@ -25,6 +25,7 @@ class Parser
const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;
private $offset = 0;
private $totalNumberOfLines;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
@ -33,11 +34,13 @@ class Parser
/**
* Constructor.
*
* @param int $offset The offset of YAML document (used for line numbers in error messages)
* @param int $offset The offset of YAML document (used for line numbers in error messages)
* @param int|null $totalNumberOfLines The overall number of lines being parsed
*/
public function __construct($offset = 0)
public function __construct($offset = 0, $totalNumberOfLines = null)
{
$this->offset = $offset;
$this->totalNumberOfLines = $totalNumberOfLines;
}
/**
@ -62,6 +65,10 @@ class Parser
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = count($this->lines);
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
@ -83,7 +90,7 @@ class Parser
$isRef = $mergeNode = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a sequence item when in a mapping');
throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
$context = 'sequence';
@ -95,7 +102,7 @@ class Parser
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
@ -104,7 +111,7 @@ class Parser
) {
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$block = $values['value'];
@ -122,7 +129,7 @@ class Parser
}
} elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a mapping item when in a sequence');
throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine);
}
$context = 'mapping';
@ -169,7 +176,7 @@ class Parser
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap);
@ -220,7 +227,7 @@ class Parser
}
} else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);
// Spec: Keys MUST be unique; first one wins.
@ -247,7 +254,7 @@ class Parser
} else {
// multiple documents are not supported
if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are not supported.');
throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine);
}
// 1-liner optionally followed by newline(s)
@ -483,7 +490,7 @@ class Parser
}
if (!array_key_exists($value, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine);
}
return $this->refs[$value];
@ -569,6 +576,8 @@ class Parser
if ($notEOF) {
$blockLines[] = '';
$this->moveToPreviousLine();
} elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) {
$blockLines[] = '';
}
// folded style
@ -675,6 +684,11 @@ class Parser
return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#';
}
private function isCurrentLineLastLineInDocument()
{
return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
}
/**
* Cleanups a YAML string to be parsed.
*
@ -752,7 +766,7 @@ class Parser
*/
private function isStringUnIndentedCollectionItem()
{
return 0 === strpos($this->currentLine, '- ');
return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- ');
}
/**

View File

@ -547,7 +547,7 @@ EOF;
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Multiple documents are not supported.
* @expectedExceptionMessageRegExp /^Multiple documents are not supported.+/
*/
public function testMultipleDocumentsNotSupportedException()
{
@ -579,6 +579,34 @@ EOF
);
}
public function testSequenceInMappingStartedBySingleDashLine()
{
$yaml = <<<EOT
a:
-
b:
-
bar: baz
- foo
d: e
EOT;
$expected = array(
'a' => array(
array(
'b' => array(
array(
'bar' => 'baz',
),
),
),
'foo',
),
'd' => 'e',
);
$this->assertSame($expected, $this->parser->parse($yaml));
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
@ -905,6 +933,7 @@ EOT
foo
# bar
baz
EOT
,
),
@ -933,7 +962,7 @@ EOT;
$expected = array(
'foo' => array(
'bar' => array(
'scalar-block' => 'line1 line2>',
'scalar-block' => "line1 line2>\n",
),
'baz' => array(
'foobar' => null,