arnaud-lb / MtHaml

Multi target HAML (HAML for PHP, Twig, <your language here>)
Other
359 stars 54 forks source link

Modular Filters implementation proposal #31

Closed ronan-gloo closed 11 years ago

ronan-gloo commented 11 years ago

A proposition to add user filters, see #19

As a proposition, i haven't wrote test right now...

Anatomy of a filter class

Filters should at least implements the MtHaml\Filter\FilterInterface. The best way is to extends your filter from MtHaml\Filter\FilterAbstract.

class PhpFilter extends  MtHaml\Filter\FilterAbstract {

    protected $name = 'php';

    // The renderer is the current renderer instance
    // $options are the environment options
    public function enter($renderer, $options)
    {
        $renderer->write('<?php')->indent();
    }

    /**
     * The parser call this method on each new line.
     * Depending on what you returns:
     * - NodeAbstract Object: the parser will treat "as it is"
     * - String: the Parser will compare the current buffer line and
     *  the string value, then replace the buffer line if String is different
     * - Void: The default parser behavior.
    */
    public function line($buffer, $options)
    {
        // The line will be treated as "raw" text.
        return new Text($buffer->getPosition(), $buffer->getLine());
    }

    // Close the filter
    public function leave($renderer, $options)
    {
        $renderer->write(' ?>'.PHP_EOL)->undent();
    }
}

// Add the filter, The filter will be available under :css
$env = new Environment('php');
$env->addFilter(new PhpFilter);

Adding Filters

  1. Through environment configuration:
$filters = array('textile' => 'Path\To\Class', 'saas' => new Saas);
$env = new Environment('php', array(), filters);
  1. Through addFilter() method:
// Add filter by class name: the class will be instanciated if filter is used
$env->addFilter('saas', 'Project\\Saas');

// Add filter by instance:
$env->addFilter(new Saas);
// you can override the instance filter name like this:
$env->addFilter('custom', new Saas);
arnaud-lb commented 11 years ago

Awesome!

I'll take a closer look at your PRs as soon as possible.

vendethiel commented 11 years ago

Looks really good, nice work! What's the use case for multiple saved indentations ?

ronan-gloo commented 11 years ago

I'm not sure to get the case. Can you provide an example, please ?

arnaud-lb commented 11 years ago

Nice work!

There is one thing we have to care about: The interface should allow to implement every possible filter (e.g. all these filters). It seems that we are missing a method taking the raw markup and returning the filtered markup, at runtime (so that #{...} work). We should try to implement some of them before merging this (e.g. the escaped filter).

I would prefer if enter/leave took the renderer as parameter. This would make filters reentrant.

We could create a FilterProvider class with an interface like this:

function getFilter($name) -> FilterInterface

And move Filter node 's getFilter logic here.

ronan-gloo commented 11 years ago

An other issue is, with the actual filter's instantiation process, is we can't instantiate a filter without a renderer. As you suggested, passing the renderer as method parameter allow us to proxy filters instantiations from the Environment, where the renderer is not available as long as we recreate it through the parser. A filter provider class is a good idea in order to care about filters availability / loading process, and inject it in the Environment class.

arnaud-lb commented 11 years ago

It looks like that filters' content can have #{ ... code ... } interpolation: http://haml.info/docs/yardoc/file.REFERENCE.html#filters . This means that for some filters we would need to do the filtering at runtime. For instance the escaped filter would need that.

hason commented 11 years ago

Any progress? This functionality is very important for me. Can I help you?

ronan-gloo commented 11 years ago

Sorry, i was very busy lasts months, and didn't took time to work on it. I'll try to finish it as soon as possible !