<commit_before><?php

namespace Boomerang\TypeExpectations;

use Boomerang\ExpectationResults\FailingExpectationResult;
use Boomerang\ExpectationResults\PassingExpectationResult;
use Boomerang\Interfaces\TypeExpectationInterface;
use Boomerang\Interfaces\ValidatorInterface;

/**
 * Structure Expectation
 *
 * Used to define rules about structure.
 *
 * @package Boomerang\TypeExpectations
 */
class StructureEx implements TypeExpectationInterface {

	protected $structure;
	protected $path = array();

	/**
	 * @var \Boomerang\Interfaces\ExpectationResultInterface[]
	 */
	protected $expectationResults = array();

	/**
	 * @var ValidatorInterface
	 */
	private $validator;

	/**
	 * @param TypeExpectationInterface|callable|mixed $structure
	 */
	function __construct( $structure ) {
		$this->structure = $structure;
	}

	/**
	 * @return ValidatorInterface
	 */
	public function getValidator() {
		return $this->validator;
	}

	/**
	 * @access private
	 * @param ValidatorInterface $validator
	 */
	public function setValidator( $validator ) {
		$this->validator = $validator;
	}

	public function match( $data ) {
		list($pass, $expectations) = $this->__validate($data, $this->structure);
		$this->addExpectationResults($expectations);

		return $pass;
	}

	/**
	 * @param       $data
	 * @param       $validation
	 * @param array $path
	 * @return array
	 */
	protected function __validate( $data, $validation, array $path = null ) {

		$expectations = array();

		if( !$path ) {
			$path = $this->path;
		}

		$pathName = $this->makePathName($path);

		$pass = true;

		if( is_array($validation) ) {
			if( is_array($data) ) {
				foreach( $validation as $key => $value ) {
					if( array_key_exists($key, $data) ) {
						list($passing, $sub_expectations) = $this->__validate($data[$key], $value, array_merge($path, array( $key )));
						$expectations = array_merge($expectations, $sub_expectations);
						$pass         = $passing && $pass;
					} else {
						$expectations[] = new FailingExpectationResult($this->validator, "Missing key\n { {$pathName} } ", $key);
					}
				}
			} else {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected scalar\n { {$pathName} } ", $validation, $data);
			}
		} elseif( $validation instanceof StructureEx ) {
			$validation->setPath($path);
			$validation->setValidator($this->validator);

			$pass         = $validation->match($data);
			$expectations = array_merge($expectations, $validation->getExpectationResults());
		} elseif( $validation instanceof TypeExpectationInterface ) {
			if( !$pass = $validation->match($data) ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected structure type check result\n { {$pathName} } ", $validation->getMatchingTypeName(), gettype($data));
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected structure type check result\n { {$pathName} } ", gettype($data));
			}

		} elseif( $validation instanceof \Closure ) {
			$result = $validation($data);
			$pass   = $result === true;
			if( !$pass ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected \\Closure structure validator result\n { {$pathName} } ", true, $result);
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected \\Closure structure validator result\n { {$pathName} } ", $result);
			}

		} elseif( is_scalar($validation) ) {
			if( !$pass = $validation == $data ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected value\n { {$pathName} } ", $validation, $data);
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected value\n { {$pathName} } ", $validation);
			}

		}

		return array( $pass, $expectations );
	}

	private function makePathName( array $path ) {
		$s_path = "root";
		foreach( $path as $loc ) {
			if( is_numeric($loc) ) {
				$s_path .= "[$loc]";
			} else {
				$s_path .= ".$loc";
			}
		}

		return $s_path;
	}

	/**
	 * @access private
	 * @param array $path
	 */
	public function setPath( array $path ) {
		$this->path = $path;
	}

	/**
	 * @access private
	 * @return \Boomerang\Interfaces\ExpectationResultInterface[]
	 */
	public function getExpectationResults() {
		return $this->expectationResults;
	}

	/**
	 * @param \Boomerang\Interfaces\ExpectationResultInterface[] $expectations
	 */
	protected function addExpectationResults( array $expectations ) {
		$this->expectationResults = array_merge($this->expectationResults, $expectations);
	}

	public function getMatchingTypeName() {
		return 'structure';
	}

}<commit_msg>StructureEx docs added<commit_after><?php

namespace Boomerang\TypeExpectations;

use Boomerang\ExpectationResults\FailingExpectationResult;
use Boomerang\ExpectationResults\PassingExpectationResult;
use Boomerang\Interfaces\TypeExpectationInterface;
use Boomerang\Interfaces\ValidatorInterface;

/**
 * Structure Expectation
 *
 * Used to define rules about structure.
 *
 * @package Boomerang\TypeExpectations
 */
class StructureEx implements TypeExpectationInterface {

	protected $structure;
	protected $path = array();

	/**
	 * @var \Boomerang\Interfaces\ExpectationResultInterface[]
	 */
	protected $expectationResults = array();

	/**
	 * @var ValidatorInterface
	 */
	private $validator;

	/**
	 * @param TypeExpectationInterface|callable|mixed $structure
	 */
	function __construct( $structure ) {
		$this->structure = $structure;
	}

	/**
	 * @return ValidatorInterface
	 */
	public function getValidator() {
		return $this->validator;
	}

	/**
	 * @access private
	 * @param ValidatorInterface $validator
	 */
	public function setValidator( $validator ) {
		$this->validator = $validator;
	}

	/**
	 * @access private
	 * 
	 * @param array|int|float|string $data
	 * @return bool
	 */
	public function match( $data ) {
		list($pass, $expectations) = $this->__validate($data, $this->structure);
		$this->addExpectationResults($expectations);

		return $pass;
	}

	/**
	 * @param array|int|float|string                                               $data
	 * @param array|int|float|string|StructureEx|TypeExpectationInterface|\Closure $validation
	 * @param array                                                                $path
	 * @return array
	 */
	protected function __validate( $data, $validation, array $path = null ) {

		$expectations = array();

		if( !$path ) {
			$path = $this->path;
		}

		$pathName = $this->makePathName($path);

		$pass = true;

		if( is_array($validation) ) {
			if( is_array($data) ) {
				foreach( $validation as $key => $value ) {
					if( array_key_exists($key, $data) ) {
						list($passing, $sub_expectations) = $this->__validate($data[$key], $value, array_merge($path, array( $key )));
						$expectations = array_merge($expectations, $sub_expectations);
						$pass         = $passing && $pass;
					} else {
						$expectations[] = new FailingExpectationResult($this->validator, "Missing key\n { {$pathName} } ", $key);
					}
				}
			} else {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected scalar\n { {$pathName} } ", $validation, $data);
			}
		} elseif( $validation instanceof StructureEx ) {
			$validation->setPath($path);
			$validation->setValidator($this->validator);

			$pass         = $validation->match($data);
			$expectations = array_merge($expectations, $validation->getExpectationResults());
		} elseif( $validation instanceof TypeExpectationInterface ) {
			if( !$pass = $validation->match($data) ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected structure type check result\n { {$pathName} } ", $validation->getMatchingTypeName(), gettype($data));
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected structure type check result\n { {$pathName} } ", gettype($data));
			}

		} elseif( $validation instanceof \Closure ) {
			$result = $validation($data);
			$pass   = $result === true;
			if( !$pass ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected \\Closure structure validator result\n { {$pathName} } ", true, $result);
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected \\Closure structure validator result\n { {$pathName} } ", $result);
			}

		} elseif( is_scalar($validation) ) {
			if( !$pass = $validation == $data ) {
				$expectations[] = new FailingExpectationResult($this->validator, "Unexpected value\n { {$pathName} } ", $validation, $data);
			} else {
				$expectations[] = new PassingExpectationResult($this->validator, "Expected value\n { {$pathName} } ", $validation);
			}

		}

		return array( $pass, $expectations );
	}

	/**
	 * @param array $path
	 * @return string
	 */
	private function makePathName( array $path ) {
		$s_path = "root";
		foreach( $path as $loc ) {
			if( is_numeric($loc) ) {
				$s_path .= "[$loc]";
			} else {
				$s_path .= ".$loc";
			}
		}

		return $s_path;
	}

	/**
	 * @access private
	 * @param array $path
	 */
	public function setPath( array $path ) {
		$this->path = $path;
	}

	/**
	 * @access private
	 * @return \Boomerang\Interfaces\ExpectationResultInterface[]
	 */
	public function getExpectationResults() {
		return $this->expectationResults;
	}

	/**
	 * @param \Boomerang\Interfaces\ExpectationResultInterface[] $expectations
	 */
	protected function addExpectationResults( array $expectations ) {
		$this->expectationResults = array_merge($this->expectationResults, $expectations);
	}

	public function getMatchingTypeName() {
		return 'structure';
	}

}
{'fraction_non_alphanumeric': 0.1521829521829522, 'fraction_numerical': 0.0, 'mean_word_length': 3.859090909090909, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1361699', 'n_tokens_mistral': 3257, 'n_tokens_neox': 2908, 'n_words': 618}