This commit is contained in:
2020-10-06 14:27:47 +07:00
commit 586be80cf6
16613 changed files with 3274099 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin arguments interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ArgumentInterface extends NodeInterface
{
}

View File

@@ -0,0 +1,112 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Background.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BackgroundNode implements ScenarioLikeInterface
{
/**
* @var string
*/
private $title;
/**
* @var StepNode[]
*/
private $steps = array();
/**
* @var string
*/
private $keyword;
/**
* @var integer
*/
private $line;
/**
* Initializes background.
*
* @param null|string $title
* @param StepNode[] $steps
* @param string $keyword
* @param integer $line
*/
public function __construct($title, array $steps, $keyword, $line)
{
$this->title = $title;
$this->steps = $steps;
$this->keyword = $keyword;
$this->line = $line;
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Background';
}
/**
* Returns background title.
*
* @return null|string
*/
public function getTitle()
{
return $this->title;
}
/**
* Checks if background has steps.
*
* @return Boolean
*/
public function hasSteps()
{
return 0 < count($this->steps);
}
/**
* Returns background steps.
*
* @return StepNode[]
*/
public function getSteps()
{
return $this->steps;
}
/**
* Returns background keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns background declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
}

View File

@@ -0,0 +1,274 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Outline Example.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExampleNode implements ScenarioInterface
{
/**
* @var string
*/
private $title;
/**
* @var string[]
*/
private $tags;
/**
* @var StepNode[]
*/
private $outlineSteps;
/**
* @var string[]
*/
private $tokens;
/**
* @var integer
*/
private $line;
/**
* @var null|StepNode[]
*/
private $steps;
/**
* @var string
*/
private $outlineTitle;
/**
* Initializes outline.
*
* @param string $title
* @param string[] $tags
* @param StepNode[] $outlineSteps
* @param string[] $tokens
* @param integer $line
* @param string|null $outlineTitle
*/
public function __construct($title, array $tags, $outlineSteps, array $tokens, $line, $outlineTitle = null)
{
$this->title = $title;
$this->tags = $tags;
$this->outlineSteps = $outlineSteps;
$this->tokens = $tokens;
$this->line = $line;
$this->outlineTitle = $outlineTitle;
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Example';
}
/**
* Returns node keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->getNodeType();
}
/**
* Returns example title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Checks if outline is tagged with tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}
/**
* Checks if outline has tags (both inherited from feature and own).
*
* @return Boolean
*/
public function hasTags()
{
return 0 < count($this->getTags());
}
/**
* Returns outline tags (including inherited from feature).
*
* @return string[]
*/
public function getTags()
{
return $this->tags;
}
/**
* Checks if outline has steps.
*
* @return Boolean
*/
public function hasSteps()
{
return 0 < count($this->outlineSteps);
}
/**
* Returns outline steps.
*
* @return StepNode[]
*/
public function getSteps()
{
return $this->steps = $this->steps ? : $this->createExampleSteps();
}
/**
* Returns example tokens.
*
* @return string[]
*/
public function getTokens()
{
return $this->tokens;
}
/**
* Returns outline declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
/**
* Returns outline title.
*
* @return string
*/
public function getOutlineTitle()
{
return $this->outlineTitle;
}
/**
* Creates steps for this example from abstract outline steps.
*
* @return StepNode[]
*/
protected function createExampleSteps()
{
$steps = array();
foreach ($this->outlineSteps as $outlineStep) {
$keyword = $outlineStep->getKeyword();
$keywordType = $outlineStep->getKeywordType();
$text = $this->replaceTextTokens($outlineStep->getText());
$args = $this->replaceArgumentsTokens($outlineStep->getArguments());
$line = $outlineStep->getLine();
$steps[] = new StepNode($keyword, $text, $args, $line, $keywordType);
}
return $steps;
}
/**
* Replaces tokens in arguments with row values.
*
* @param ArgumentInterface[] $arguments
*
* @return ArgumentInterface[]
*/
protected function replaceArgumentsTokens(array $arguments)
{
foreach ($arguments as $num => $argument) {
if ($argument instanceof TableNode) {
$arguments[$num] = $this->replaceTableArgumentTokens($argument);
}
if ($argument instanceof PyStringNode) {
$arguments[$num] = $this->replacePyStringArgumentTokens($argument);
}
}
return $arguments;
}
/**
* Replaces tokens in table with row values.
*
* @param TableNode $argument
*
* @return TableNode
*/
protected function replaceTableArgumentTokens(TableNode $argument)
{
$table = $argument->getTable();
foreach ($table as $line => $row) {
foreach (array_keys($row) as $col) {
$table[$line][$col] = $this->replaceTextTokens($table[$line][$col]);
}
}
return new TableNode($table);
}
/**
* Replaces tokens in PyString with row values.
*
* @param PyStringNode $argument
*
* @return PyStringNode
*/
protected function replacePyStringArgumentTokens(PyStringNode $argument)
{
$strings = $argument->getStrings();
foreach ($strings as $line => $string) {
$strings[$line] = $this->replaceTextTokens($strings[$line]);
}
return new PyStringNode($strings, $argument->getLine());
}
/**
* Replaces tokens in text with row values.
*
* @param string $text
*
* @return string
*/
protected function replaceTextTokens($text)
{
foreach ($this->tokens as $key => $val) {
$text = str_replace('<' . $key . '>', $val, $text);
}
return $text;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Outline Example Table.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExampleTableNode extends TableNode
{
/**
* @var string
*/
private $keyword;
/**
* Initializes example table.
*
* @param array $table Table in form of [$rowLineNumber => [$val1, $val2, $val3]]
* @param string $keyword
*/
public function __construct(array $table, $keyword)
{
$this->keyword = $keyword;
parent::__construct($table);
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'ExampleTable';
}
/**
* Returns example table keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
}

View File

@@ -0,0 +1,243 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Feature.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FeatureNode implements KeywordNodeInterface, TaggedNodeInterface
{
/**
* @var null|string
*/
private $title;
/**
* @var null|string
*/
private $description;
/**
* @var string[]
*/
private $tags = array();
/**
* @var null|BackgroundNode
*/
private $background;
/**
* @var ScenarioInterface[]
*/
private $scenarios = array();
/**
* @var string
*/
private $keyword;
/**
* @var string
*/
private $language;
/**
* @var null|string
*/
private $file;
/**
* @var integer
*/
private $line;
/**
* Initializes feature.
*
* @param null|string $title
* @param null|string $description
* @param string[] $tags
* @param null|BackgroundNode $background
* @param ScenarioInterface[] $scenarios
* @param string $keyword
* @param string $language
* @param null|string $file
* @param integer $line
*/
public function __construct(
$title,
$description,
array $tags,
BackgroundNode $background = null,
array $scenarios,
$keyword,
$language,
$file,
$line
) {
$this->title = $title;
$this->description = $description;
$this->tags = $tags;
$this->background = $background;
$this->scenarios = $scenarios;
$this->keyword = $keyword;
$this->language = $language;
$this->file = $file;
$this->line = $line;
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Feature';
}
/**
* Returns feature title.
*
* @return null|string
*/
public function getTitle()
{
return $this->title;
}
/**
* Checks if feature has a description.
*
* @return Boolean
*/
public function hasDescription()
{
return !empty($this->description);
}
/**
* Returns feature description.
*
* @return null|string
*/
public function getDescription()
{
return $this->description;
}
/**
* Checks if feature is tagged with tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->tags);
}
/**
* Checks if feature has tags.
*
* @return Boolean
*/
public function hasTags()
{
return 0 < count($this->tags);
}
/**
* Returns feature tags.
*
* @return string[]
*/
public function getTags()
{
return $this->tags;
}
/**
* Checks if feature has background.
*
* @return Boolean
*/
public function hasBackground()
{
return null !== $this->background;
}
/**
* Returns feature background.
*
* @return null|BackgroundNode
*/
public function getBackground()
{
return $this->background;
}
/**
* Checks if feature has scenarios.
*
* @return Boolean
*/
public function hasScenarios()
{
return 0 < count($this->scenarios);
}
/**
* Returns feature scenarios.
*
* @return ScenarioInterface[]
*/
public function getScenarios()
{
return $this->scenarios;
}
/**
* Returns feature keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns feature language.
*
* @return string
*/
public function getLanguage()
{
return $this->language;
}
/**
* Returns feature file.
*
* @return null|string
*/
public function getFile()
{
return $this->file;
}
/**
* Returns feature declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin keyword node interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface KeywordNodeInterface extends NodeInterface
{
/**
* Returns node keyword.
*
* @return string
*/
public function getKeyword();
/**
* Returns node title.
*
* @return null|string
*/
public function getTitle();
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin node interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface NodeInterface
{
/**
* Returns node type string
*
* @return string
*/
public function getNodeType();
/**
* Returns feature declaration line number.
*
* @return integer
*/
public function getLine();
}

View File

@@ -0,0 +1,218 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Outline.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutlineNode implements ScenarioInterface
{
/**
* @var string
*/
private $title;
/**
* @var string[]
*/
private $tags;
/**
* @var StepNode[]
*/
private $steps;
/**
* @var ExampleTableNode
*/
private $table;
/**
* @var string
*/
private $keyword;
/**
* @var integer
*/
private $line;
/**
* @var null|ExampleNode[]
*/
private $examples;
/**
* Initializes outline.
*
* @param null|string $title
* @param string[] $tags
* @param StepNode[] $steps
* @param ExampleTableNode $table
* @param string $keyword
* @param integer $line
*/
public function __construct(
$title,
array $tags,
array $steps,
ExampleTableNode $table,
$keyword,
$line
) {
$this->title = $title;
$this->tags = $tags;
$this->steps = $steps;
$this->table = $table;
$this->keyword = $keyword;
$this->line = $line;
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Outline';
}
/**
* Returns outline title.
*
* @return null|string
*/
public function getTitle()
{
return $this->title;
}
/**
* Checks if outline is tagged with tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}
/**
* Checks if outline has tags (both inherited from feature and own).
*
* @return Boolean
*/
public function hasTags()
{
return 0 < count($this->getTags());
}
/**
* Returns outline tags (including inherited from feature).
*
* @return string[]
*/
public function getTags()
{
return $this->tags;
}
/**
* Checks if outline has steps.
*
* @return Boolean
*/
public function hasSteps()
{
return 0 < count($this->steps);
}
/**
* Returns outline steps.
*
* @return StepNode[]
*/
public function getSteps()
{
return $this->steps;
}
/**
* Checks if outline has examples.
*
* @return Boolean
*/
public function hasExamples()
{
return 0 < count($this->table->getColumnsHash());
}
/**
* Returns examples table.
*
* @return ExampleTableNode
*/
public function getExampleTable()
{
return $this->table;
}
/**
* Returns list of examples for the outline.
*
* @return ExampleNode[]
*/
public function getExamples()
{
return $this->examples = $this->examples ? : $this->createExamples();
}
/**
* Returns outline keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns outline declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
/**
* Creates examples for this outline using examples table.
*
* @return ExampleNode[]
*/
protected function createExamples()
{
$examples = array();
foreach ($this->table->getColumnsHash() as $rowNum => $row) {
$examples[] = new ExampleNode(
$this->table->getRowAsString($rowNum + 1),
$this->tags,
$this->getSteps(),
$row,
$this->table->getRowLine($rowNum + 1),
$this->getTitle()
);
}
return $examples;
}
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin PyString argument.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PyStringNode implements ArgumentInterface
{
/**
* @var array
*/
private $strings = array();
/**
* @var integer
*/
private $line;
/**
* Initializes PyString.
*
* @param array $strings String in form of [$stringLine]
* @param integer $line Line number where string been started
*/
public function __construct(array $strings, $line)
{
$this->strings = $strings;
$this->line = $line;
}
/**
* Returns node type.
*
* @return string
*/
public function getNodeType()
{
return 'PyString';
}
/**
* Returns entire PyString lines set.
*
* @return array
*/
public function getStrings()
{
return $this->strings;
}
/**
* Returns raw string.
*
* @return string
*/
public function getRaw()
{
return implode("\n", $this->strings);
}
/**
* Converts PyString into string.
*
* @return string
*/
public function __toString()
{
return $this->getRaw();
}
/**
* Returns line number at which PyString was started.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin scenario interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ScenarioInterface extends ScenarioLikeInterface, TaggedNodeInterface
{
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin scenario-like interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ScenarioLikeInterface extends KeywordNodeInterface, StepContainerInterface
{
}

View File

@@ -0,0 +1,150 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Represents Gherkin Scenario.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ScenarioNode implements ScenarioInterface
{
/**
* @var string
*/
private $title;
/**
* @var array
*/
private $tags = array();
/**
* @var StepNode[]
*/
private $steps = array();
/**
* @var string
*/
private $keyword;
/**
* @var integer
*/
private $line;
/**
* Initializes scenario.
*
* @param null|string $title
* @param array $tags
* @param StepNode[] $steps
* @param string $keyword
* @param integer $line
*/
public function __construct($title, array $tags, array $steps, $keyword, $line)
{
$this->title = $title;
$this->tags = $tags;
$this->steps = $steps;
$this->keyword = $keyword;
$this->line = $line;
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Scenario';
}
/**
* Returns scenario title.
*
* @return null|string
*/
public function getTitle()
{
return $this->title;
}
/**
* Checks if scenario is tagged with tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}
/**
* Checks if scenario has tags (both inherited from feature and own).
*
* @return Boolean
*/
public function hasTags()
{
return 0 < count($this->getTags());
}
/**
* Returns scenario tags (including inherited from feature).
*
* @return array
*/
public function getTags()
{
return $this->tags;
}
/**
* Checks if scenario has steps.
*
* @return Boolean
*/
public function hasSteps()
{
return 0 < count($this->steps);
}
/**
* Returns scenario steps.
*
* @return StepNode[]
*/
public function getSteps()
{
return $this->steps;
}
/**
* Returns scenario keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns scenario declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin step container interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface StepContainerInterface extends NodeInterface
{
/**
* Checks if container has steps.
*
* @return Boolean
*/
public function hasSteps();
/**
* Returns container steps.
*
* @return StepNode[]
*/
public function getSteps();
}

View File

@@ -0,0 +1,152 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
use Behat\Gherkin\Exception\NodeException;
/**
* Represents Gherkin Step.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class StepNode implements NodeInterface
{
/**
* @var string
*/
private $keyword;
/**
* @var string
*/
private $keywordType;
/**
* @var string
*/
private $text;
/**
* @var ArgumentInterface[]
*/
private $arguments = array();
/**
* @var integer
*/
private $line;
/**
* Initializes step.
*
* @param string $keyword
* @param string $text
* @param ArgumentInterface[] $arguments
* @param integer $line
* @param string $keywordType
*/
public function __construct($keyword, $text, array $arguments, $line, $keywordType = null)
{
if (count($arguments) > 1) {
throw new NodeException(sprintf(
'Steps could have only one argument, but `%s %s` have %d.',
$keyword,
$text,
count($arguments)
));
}
$this->keyword = $keyword;
$this->text = $text;
$this->arguments = $arguments;
$this->line = $line;
$this->keywordType = $keywordType ?: 'Given';
}
/**
* Returns node type string
*
* @return string
*/
public function getNodeType()
{
return 'Step';
}
/**
* Returns step keyword in provided language (Given, When, Then, etc.).
*
* @return string
*
* @deprecated use getKeyword() instead
*/
public function getType()
{
return $this->getKeyword();
}
/**
* Returns step keyword in provided language (Given, When, Then, etc.).
*
* @return string
*
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns step type keyword (Given, When, Then, etc.).
*
* @return string
*/
public function getKeywordType()
{
return $this->keywordType;
}
/**
* Returns step text.
*
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* Checks if step has arguments.
*
* @return Boolean
*/
public function hasArguments()
{
return 0 < count($this->arguments);
}
/**
* Returns step arguments.
*
* @return ArgumentInterface[]
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Returns step declaration line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
}

View File

@@ -0,0 +1,342 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
use ArrayIterator;
use Behat\Gherkin\Exception\NodeException;
use Iterator;
use IteratorAggregate;
/**
* Represents Gherkin Table argument.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class TableNode implements ArgumentInterface, IteratorAggregate
{
/**
* @var array
*/
private $table;
/**
* @var integer
*/
private $maxLineLength = array();
/**
* Initializes table.
*
* @param array $table Table in form of [$rowLineNumber => [$val1, $val2, $val3]]
*
* @throws NodeException If the given table is invalid
*/
public function __construct(array $table)
{
$this->table = $table;
$columnCount = null;
foreach ($this->getRows() as $row) {
if ($columnCount === null) {
$columnCount = count($row);
}
if (count($row) !== $columnCount) {
throw new NodeException('Table does not have same number of columns in every row.');
}
if (!is_array($row)) {
throw new NodeException('Table is not two-dimensional.');
}
foreach ($row as $column => $string) {
if (!isset($this->maxLineLength[$column])) {
$this->maxLineLength[$column] = 0;
}
if (!is_scalar($string)) {
throw new NodeException('Table is not two-dimensional.');
}
$this->maxLineLength[$column] = max($this->maxLineLength[$column], mb_strlen($string, 'utf8'));
}
}
}
/**
* Creates a table from a given list.
*
* @param array $list One-dimensional array
*
* @return TableNode
*
* @throws NodeException If the given list is not a one-dimensional array
*/
public static function fromList(array $list)
{
if (count($list) !== count($list, COUNT_RECURSIVE)) {
throw new NodeException('List is not a one-dimensional array.');
}
array_walk($list, function (&$item) {
$item = array($item);
});
return new self($list);
}
/**
* Returns node type.
*
* @return string
*/
public function getNodeType()
{
return 'Table';
}
/**
* Returns table hash, formed by columns (ColumnsHash).
*
* @return array
*/
public function getHash()
{
return $this->getColumnsHash();
}
/**
* Returns table hash, formed by columns.
*
* @return array
*/
public function getColumnsHash()
{
$rows = $this->getRows();
$keys = array_shift($rows);
$hash = array();
foreach ($rows as $row) {
$hash[] = array_combine($keys, $row);
}
return $hash;
}
/**
* Returns table hash, formed by rows.
*
* @return array
*/
public function getRowsHash()
{
$hash = array();
foreach ($this->getRows() as $row) {
$hash[array_shift($row)] = (1 == count($row)) ? $row[0] : $row;
}
return $hash;
}
/**
* Returns numerated table lines.
* Line numbers are keys, lines are values.
*
* @return array
*/
public function getTable()
{
return $this->table;
}
/**
* Returns table rows.
*
* @return array
*/
public function getRows()
{
return array_values($this->table);
}
/**
* Returns table definition lines.
*
* @return array
*/
public function getLines()
{
return array_keys($this->table);
}
/**
* Returns specific row in a table.
*
* @param integer $index Row number
*
* @return array
*
* @throws NodeException If row with specified index does not exist
*/
public function getRow($index)
{
$rows = $this->getRows();
if (!isset($rows[$index])) {
throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
}
return $rows[$index];
}
/**
* Returns specific column in a table.
*
* @param integer $index Column number
*
* @return array
*
* @throws NodeException If column with specified index does not exist
*/
public function getColumn($index)
{
if ($index >= count($this->getRow(0))) {
throw new NodeException(sprintf('Column #%d does not exist in table.', $index));
}
$rows = $this->getRows();
$column = array();
foreach ($rows as $row) {
$column[] = $row[$index];
}
return $column;
}
/**
* Returns line number at which specific row was defined.
*
* @param integer $index
*
* @return integer
*
* @throws NodeException If row with specified index does not exist
*/
public function getRowLine($index)
{
$lines = array_keys($this->table);
if (!isset($lines[$index])) {
throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
}
return $lines[$index];
}
/**
* Converts row into delimited string.
*
* @param integer $rowNum Row number
*
* @return string
*/
public function getRowAsString($rowNum)
{
$values = array();
foreach ($this->getRow($rowNum) as $column => $value) {
$values[] = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);
}
return sprintf('|%s|', implode('|', $values));
}
/**
* Converts row into delimited string.
*
* @param integer $rowNum Row number
* @param callable $wrapper Wrapper function
*
* @return string
*/
public function getRowAsStringWithWrappedValues($rowNum, $wrapper)
{
$values = array();
foreach ($this->getRow($rowNum) as $column => $value) {
$value = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);
$values[] = call_user_func($wrapper, $value, $column);
}
return sprintf('|%s|', implode('|', $values));
}
/**
* Converts entire table into string
*
* @return string
*/
public function getTableAsString()
{
$lines = array();
for ($i = 0; $i < count($this->getRows()); $i++) {
$lines[] = $this->getRowAsString($i);
}
return implode("\n", $lines);
}
/**
* Returns line number at which table was started.
*
* @return integer
*/
public function getLine()
{
return $this->getRowLine(0);
}
/**
* Converts table into string
*
* @return string
*/
public function __toString()
{
return $this->getTableAsString();
}
/**
* Retrieves a hash iterator.
*
* @return Iterator
*/
public function getIterator()
{
return new ArrayIterator($this->getHash());
}
/**
* Pads string right.
*
* @param string $text Text to pad
* @param integer $length Length
*
* @return string
*/
protected function padRight($text, $length)
{
while ($length > mb_strlen($text, 'utf8')) {
$text = $text . ' ';
}
return $text;
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Node;
/**
* Gherkin tagged node interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface TaggedNodeInterface extends NodeInterface
{
/**
* Checks if node is tagged with tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag);
/**
* Checks if node has tags (both inherited from feature and own).
*
* @return Boolean
*/
public function hasTags();
/**
* Returns node tags (including inherited from feature).
*
* @return string[]
*/
public function getTags();
}