<commit_before><?php
namespace Testo;

use Testo\Filter\FilterInterface;
use Testo\Filter\LeaveBlocksFilter;
use Testo\Filter\UncommentFilter;
use Testo\Source\ClassSource;
use Testo\Source\FileSource;
use Testo\Source\MethodSource;
use Testo\Source\RootDirAwareInterface;
use Testo\Source\SourceInterface;

class Testo implements RootDirAwareInterface
{
    protected $beginBlockTag = "<!-- begin -->\n";
    protected $endBlockTag = "<!-- end -->\n";
    /**
     * @var SourceInterface[]
     */
    protected $sources;

    /**
     * @var FilterInterface[]
     */
    protected $filters;

    /**
     * @var string
     */
    protected $rootDir;

    public function __construct()
    {
        $this->filters = array();
        $this->filters[] = new UncommentFilter();
        $this->filters[] = new LeaveBlocksFilter();

        $this->sources = array();
        $this->sources[] = new FileSource($this);
        $this->sources[] = new ClassSource();
        $this->sources[] = new MethodSource();

    }

    public function generate($documentFile)
    {
        $this->rootDir = dirname($documentFile);

        $document = array();
        $documentLines = file($documentFile);
        for ($i = 0, $n = count($documentLines); $i < $n; $i++) {
            $line = $documentLines[$i];
            $document[] = $line;
            foreach ($this->sources as $source) {
                $content = $source->getContent($line);
                if (is_array($content)) {
                    foreach ($this->filters as $filter) {
                        $content = $filter->filter($content);
                    }
                    if ($this->isBeginBlockTag($documentLines[$i + 1])) {
                        while (!$this->isEndBlockTag($documentLines[++$i])) {
                        }
                    }
                    $document[] = $this->beginBlockTag;
                    $document[] = $this->unShiftCode(implode($content));
                    $document[] = $this->endBlockTag;
                }
            }
        }

        file_put_contents($documentFile, implode('', $document));
    }

    /**
     * @param string $code
     * @return string
     */
    protected function unShiftCode($code)
    {
        $code = trim($code, "\n") . "\n";
        $placeholders = array();
        if (preg_match('/^(\s*?)[^\s]/', $code, $placeholders)) {
            $code = preg_replace("/^$placeholders[1]/", '', $code);
            $code = str_replace("\n$placeholders[1]", "\n", $code);
        }

        return $code;
    }

    /**<commit_msg>there is no need in templates. generated code is placed after testo-lines (not instead). generated code is wrapped by `<!-- begin --> .. <!-- end -->` tags.<commit_after><?php
namespace Testo;

use Testo\Filter\FilterInterface;
use Testo\Filter\LeaveBlocksFilter;
use Testo\Filter\UncommentFilter;
use Testo\Source\ClassSource;
use Testo\Source\FileSource;
use Testo\Source\MethodSource;
use Testo\Source\RootDirAwareInterface;
use Testo\Source\SourceInterface;

class Testo implements RootDirAwareInterface
{
    protected $beginBlockTag = "<!-- begin -->\n";
    protected $endBlockTag = "<!-- end -->\n";
    /**
     * @var SourceInterface[]
     */
    protected $sources;

    /**
     * @var FilterInterface[]
     */
    protected $filters;

    /**
     * @var string
     */
    protected $rootDir;

    public function __construct()
    {
        $this->filters = array();
        $this->filters[] = new UncommentFilter();
        $this->filters[] = new LeaveBlocksFilter();

        $this->sources = array();
        $this->sources[] = new FileSource($this);
        $this->sources[] = new ClassSource();
        $this->sources[] = new MethodSource();

    }

    public function generate($documentFile)
    {
        $this->rootDir = dirname($documentFile);

        $document = array();
        $documentLines = file($documentFile);
        for ($i = 0, $n = count($documentLines); $i < $n; $i++) {
            $line = $documentLines[$i];
            $document[] = $line;
            foreach ($this->sources as $source) {
                $content = $source->getContent($line);
                if (is_array($content)) {
                    foreach ($this->filters as $filter) {
                        $content = $filter->filter($content);
                    }
                    if ($this->isBeginBlockTag($documentLines[$i + 1])) {
                        while (!$this->isEndBlockTag($documentLines[++$i])) {
                        }
                    }
                    
                    $document[] = $this->beginBlockTag;
                    $document[] = $this->unShiftCode(implode($content));
                    $document[] = $this->endBlockTag;
                }
            }
        }

        file_put_contents($documentFile, implode('', $document));
    }

    /**
     * @param string $code
     * @return string
     */
    protected function unShiftCode($code)
    {
        $code = trim($code, "\n") . "\n";
        $placeholders = array();
        if (preg_match('/^(\s*?)[^\s]/', $code, $placeholders)) {
            $code = preg_replace("/^$placeholders[1]/", '', $code);
            $code = str_replace("\n$placeholders[1]", "\n", $code);
        }

        return $code;
    }

    /**
{'fraction_non_alphanumeric': 0.16226415094339622, 'fraction_numerical': 0.0015094339622641509, 'mean_word_length': 1.9126373626373627, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 43, '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': '1262172', 'n_tokens_mistral': 1510, 'n_tokens_neox': 1458, 'n_words': 303}