<commit_before><?php
require_once('class.hooks.php');

/**
 * @page template1 Template Class
 *
 * Basic templating functionality
 *
 * @section usage Usage
 *
 * index.php
 * @code
 *	require_once('include/sleepy.php');
 *
 *	$page = new Template('templates/default.tpl');
 *	$page->bind('title', 'Sleepy Mustache');
 *	$page->bind('header', 'Hello world!');
 *	$page->show();
 * @endcode
 *
 * default.tpl
 * @code
 * 	<html>
 *		<head>
 *			<title>{{ title }}</title>
 *		</head>
 *		<body>
 *			<h1>{{ header }}</h1>
 *			<p>This page has been viewed {{ hits }} times.</p>
 *		</body>
 *	</html>
 * @endcode
 *
 * @section changelog Changelog
 * * added bindStart() and bindStart() for capturing large amounts of HTML
 *
 * @todo add #if
 *
 * @date		September 17, 2013
 * @author		<NAME> <<EMAIL>>
 * @version		1.4
 * @copyright	GPL 3 http://cuttingedgecode.com
 */

class Template {
	/**
	 * string The extension for template files
	 */
	public $extension = ".tpl";

	/**
	 * string The template directory
	 */
	public $directory;

	/**
	 * string The template file
	 * @protected
	 */
	protected $_file;

	/**
	 * array The data bound to the template
	 * @protected
	 */
	protected $_data = array();

	/**
	 * Does the template exist?
	 * @param  string $file Name of template
	 * @return Bool         True if template exists
	 * @private
	 */
	private function checkTemplate($file) {
		if (!file_exists($this->directory . $file . $this->extension)) {
			throw new Exception("Template " . $this->directory . $this->_file . $this->extension . " doesn't exist.");
		}

		return true;
	}

	/**
	 * Given a path, the function returns a piece of $arr. For example
	 * 'name.first' will return $arr['name']['first']
	 * @param  array  $arr  An array to search using the $path
	 * @param  string $path A path representing the dimensions of the array
	 * @return mixed        A sub-array or string
	 */
	private function assignArrayByPath(&$arr, $path) {
		$keys = explode('.', $path);

		while ($key = array_shift($keys)) {
			$a = &$arr[$key];
		}

		return $a;
	}

	/**
	 * Sets the template to use.
	 * @param [type] $file [description]
	 */
	public function setTemplate($file) {
		$this->_file = $file;
	}

	/**
	 * Renders the template
	 * @param  string $template The template to render
	 * @param  array $data      The data bound to the template
	 * @return string           The rendered template
	 */
	private function render($template, $data) {

		// Process the includes
		if (preg_match('/{{\s*#include\s.*}}/', $template, $include)) {
			$index = trim(str_replace('{{', '', str_replace('}}', '', $include[0])));
			if (file_exists($this->directory . str_replace('#include ', '', $index) . $this->extension)) {
				ob_start();
				include($this->directory . str_replace('#include ', '', $index) . $this->extension);
			} else {
				ob_clean(); // clear buffer in $this->show();
				throw new Exception($this->directory . str_replace('#include ', '', $index) . $this->extension . " doesn't exist. Cannot include file.");
			}
			$template = str_replace($include[0], $this->render(ob_get_contents(), $data), $template);
			ob_end_clean();

			return $this->render($template, $data);
		}

		// Process the #each blocks
		if (preg_match_all('/{{\s?#each.+?}}(?:(?>[^{}]+)|(?R))*{{\s?\/each\s?}}/ism', $template, $loops)) {
			// For every #each
			foreach ($loops[0] as $value) {
				// Reset rendered data
				$rendered = "";

				// Stores the values of <for> and <in> into $forin
				preg_match('/{{\s?#each\s(?<for>\w+) in (?<in>.*?)\s?}}/', $value, $forin);

				// Removes the each loop
				$new_template = preg_replace('/{{\s?#each.*?}}/s', '', $value, 1);
				$new_template = preg_replace('/{{\s?\/each\s?}}$/s', '', $new_template, 1);

				// get the array based on the <in>
				$in = $this->assignArrayByPath($data, $forin['in']);

				// for each changelog
				if (is_array($in[0])) {
					foreach ($in as $new_data) {
						// Make the $new_data match the <for>
						$new_data[$forin['for']] =  $new_data;

						// render the new template
						$rendered = $rendered . $this->render($new_template, $new_data);
					}
				} else {
					foreach ($in as $string) {
						$new_data[$forin['for']] = $string;
						$rendered = $rendered . $this->render($new_template, $new_data);
					}

					// render the new template
					$rendered = $rendered . $this->render($new_template, array_merge($new_data, $data));
				}

				$template = str_replace($value, $rendered, $template);
			}
		}

		$template = Hook::addFilter('prerender_template', $template);

		// Find all the single placeholders
		preg_match_all('/{{\s?(.*?)(\s.*?)?\s?}}/', $template, $matches);

		// For each replace with a value
		foreach (array_unique($matches[0]) as $index => $placeholder) {
			$key = strtolower($matches[1][$index]); //trim(str_replace('{{', '', str_replace('}}', '', $placeholder)));

			// make sure it isn't an array. We use #each for those.
			if (@is_array($data[$key])) {
				throw new Exception("Arrays can only be bound in #each loops. Placeholder: {$key}");
			}

			$arguments = array(
				$this->assignArrayByPath($data, $key)
			);

			$arguments = array_merge($arguments, explode(" ", $matches[2][$index]));	

			$template = str_replace($placeholder, Hook::addFilter('render_placeholder_' . strtolower($key), $arguments), $template);
		}

		return $template;
	}
<commit_msg>Add template_each_array filter, iterator, zebra<commit_after><?php
require_once('class.hooks.php');

/**
 * @page template1 Template Class
 *
 * Basic templating functionality
 *
 * @section usage Usage
 *
 * index.php
 * @code
 *	require_once('include/sleepy.php');
 *
 *	$page = new Template('templates/default.tpl');
 *	$page->bind('title', 'Sleepy Mustache');
 *	$page->bind('header', 'Hello world!');
 *	$page->show();
 * @endcode
 *
 * default.tpl
 * @code
 * 	<html>
 *		<head>
 *			<title>{{ title }}</title>
 *		</head>
 *		<body>
 *			<h1>{{ header }}</h1>
 *			<p>This page has been viewed {{ hits }} times.</p>
 *		</body>
 *	</html>
 * @endcode
 *
 * @section changelog Changelog
 * * added bindStart() and bindStart() for capturing large amounts of HTML
 *
 * @todo add #if
 *
 * @date		September 17, 2013
 * @author		<NAME> <<EMAIL>>
 * @version		1.4
 * @copyright	GPL 3 http://cuttingedgecode.com
 */

class Template {
	/**
	 * string The extension for template files
	 */
	public $extension = ".tpl";

	/**
	 * string The template directory
	 */
	public $directory;

	/**
	 * string The template file
	 * @protected
	 */
	protected $_file;

	/**
	 * array The data bound to the template
	 * @protected
	 */
	protected $_data = array();

	/**
	 * Does the template exist?
	 * @param  string $file Name of template
	 * @return Bool         True if template exists
	 * @private
	 */
	private function checkTemplate($file) {
		if (!file_exists($this->directory . $file . $this->extension)) {
			throw new Exception("Template " . $this->directory . $this->_file . $this->extension . " doesn't exist.");
		}

		return true;
	}

	/**
	 * Given a path, the function returns a piece of $arr. For example
	 * 'name.first' will return $arr['name']['first']
	 * @param  array  $arr  An array to search using the $path
	 * @param  string $path A path representing the dimensions of the array
	 * @return mixed        A sub-array or string
	 */
	private function assignArrayByPath(&$arr, $path) {
		$keys = explode('.', $path);

		while ($key = array_shift($keys)) {
			$a = &$arr[$key];
		}

		return $a;
	}

	/**
	 * Sets the template to use.
	 * @param [type] $file [description]
	 */
	public function setTemplate($file) {
		$this->_file = $file;
	}

	/**
	 * Renders the template
	 * @param  string $template The template to render
	 * @param  array $data      The data bound to the template
	 * @return string           The rendered template
	 */
	private function render($template, $data) {

		// Process the includes
		if (preg_match('/{{\s*#include\s.*}}/', $template, $include)) {
			$index = trim(str_replace('{{', '', str_replace('}}', '', $include[0])));
			if (file_exists($this->directory . str_replace('#include ', '', $index) . $this->extension)) {
				ob_start();
				include($this->directory . str_replace('#include ', '', $index) . $this->extension);
			} else {
				ob_clean(); // clear buffer in $this->show();
				throw new Exception($this->directory . str_replace('#include ', '', $index) . $this->extension . " doesn't exist. Cannot include file.");
			}
			$template = str_replace($include[0], $this->render(ob_get_contents(), $data), $template);
			ob_end_clean();

			return $this->render($template, $data);
		}

		// Process the #each blocks
		if (preg_match_all('/{{\s?#each.+?}}(?:(?>[^{}]+)|(?R))*{{\s?\/each\s?}}/ism', $template, $loops)) {
			// For every #each
			foreach ($loops[0] as $value) {
				// Reset rendered data
				$rendered = "";

				// Stores the values of <for> and <in> into $forin
				preg_match('/{{\s?#each\s(?<for>\w+) in (?<in>.*?)\s?}}/', $value, $forin);

				// Removes the each loop
				$new_template = preg_replace('/{{\s?#each.*?}}/s', '', $value, 1);
				$new_template = preg_replace('/{{\s?\/each\s?}}$/s', '', $new_template, 1);

				// get the array based on the <in>
				$in = $this->assignArrayByPath($data, $forin['in']);

				// for each changelog
				if (is_array($in[0])) {

					// Allow hooks to edit the data
					$in = Hook::addFilter('template_each_array', array($in));

					$iterator = 0;

					foreach ($in as $new_data) {
						$iterator++;

						$new_data = Hook::addFilter('template_each', array($new_data));
						$new_data = Hook::addFilter('template_each_' + $forin['for'], array($new_data));

						$new_data['iterator'] = $iterator;
						$new_data['zebra'] = ($iterator % 2) ? 'odd' : 'even';

						// Make the $new_data match the <for>
						$new_data[$forin['for']] =  $new_data;

						// render the new template
						$rendered = $rendered . $this->render($new_template, $new_data);
					}
				} else {
					foreach ($in as $string) {
						$new_data[$forin['for']] = $string;
						$rendered = $rendered . $this->render($new_template, $new_data);
					}

					// render the new template
					$rendered = $rendered . $this->render($new_template, array_merge($new_data, $data));
				}

				$template = str_replace($value, $rendered, $template);
			}
		}

		$template = Hook::addFilter('prerender_template', $template);

		// Find all the single placeholders
		preg_match_all('/{{\s?(.*?)(\s.*?)?\s?}}/', $template, $matches);

		// For each replace with a value
		foreach (array_unique($matches[0]) as $index => $placeholder) {
			$key = strtolower($matches[1][$index]);

			$arguments = array(
				$this->assignArrayByPath($data, $key)
			);

			$arguments = array_merge($arguments, explode(" ", $matches[2][$index]));	

			$template = str_replace($placeholder, Hook::addFilter('render_placeholder_' . strtolower($key), $arguments), $template);
		}

		return $template;
	}

{'fraction_non_alphanumeric': 0.1926270645131855, 'fraction_numerical': 0.004014964869057396, 'mean_word_length': 3.279578289730574, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 95, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1431311', 'n_tokens_mistral': 4143, 'n_tokens_neox': 3571, 'n_words': 932}