Come definire le direttive del modello (dal punto di vista dell'API)?

2

Prefazione

Sto scrivendo un linguaggio template (non preoccuparmi di cercare di parlarmi), e in esso ci sono due tipi di nodi estensibili dall'utente. TemplateTags e TemplateDirectives.

Un TemplateTag si riferisce strettamente a un tag HTML - potrebbe sembrare qualcosa di simile

div(class="green") { "content" }

E sarà reso come

<div class="green">content</div>

vale a dire, ci vuole un sacco di attributi, oltre ad alcuni contenuti, e sputa un po 'di HTML.

I TemplateDirectives sono un po 'più complicati. Possono essere cose come for loops, ifs , includes e altre cose simili. Loro sembrano molto simili a un TemplateTag, ma devono essere elaborati in modo diverso. Ad esempio,

@for($i in $items) {
   div(class="green") { $i }
}

Cicli su $items e genera il contenuto con la variabile $i sostituita ogni volta.

Quindi ... Sto cercando di definire un modo per definire queste direttive ora.

Tag modello

I TemplateTags sono abbastanza facili da scrivere. Sembrano qualcosa del genere:

[TemplateTag]
static string div(string content = null, object attrs = null)
{
    return HtmlTag("div", content, attrs);
}

Dove content ottiene le cose tra le parentesi graffe (pre-renderizzate se ci sono variabili e così via) e attrs è o una Dictionary<string,object> di attributi, o un tipo anonimo usato come un dizionario. Restituisce solo l'HTML che viene inserito al suo posto. Semplice! Puoi scrivere tag in fondamentalmente su 1 riga.

Direttive sui modelli

Il modo in cui li ho definiti ora è simile a questo:

[TemplateDirective]
static string @for(string @params, string content)
{
    var tokens = Regex.Split(@params, @"\sin\s").Select(s => s.Trim()).ToArray();
    string itemName = tokens[0].Substring(1);
    string enumName = tokens[1].Substring(1);
    var enumerable = data[enumName] as IEnumerable;
    var sb = new StringBuilder();
    var template = new Template(content);
    foreach (var item in enumerable)
    {
        var templateVars = new Dictionary<string, object>(data) { { itemName, item } };
        sb.Append(template.Render(templateVars));
    }
    return sb.ToString();
}

(Esempio di lavoro). Fondamentalmente, il materiale tra ( e ) è non diviso automaticamente in argomenti (come i tag del modello), e content non è pre-renderizzato.

La ragione per cui non è pre-renderizzata è perché potresti voler aggiungere o rimuovere alcune variabili di template o qualcosa prima. In questo caso, aggiungiamo la variabile $i alle variabili del modello,

var templateVars = new Dictionary<string, object>(data) { { itemName, item } };

E quindi esegui il rendering del contenuto manualmente,

sb.Append(template.Render(templateVars));

Domanda

Mi chiedo se questo è l'approccio migliore per definire le direttive Template personalizzate. Voglio renderlo il più semplice possibile. Cosa succede se l'utente non sa come eseguire il rendering dei modelli o non sa che dovrebbe?

Forse dovrei passare in un'istanza Template pre-riempita con content invece? O forse lascialo solo manomettere le variabili del template e poi renderizzare automaticamente il contenuto alla fine?

OTOH, per cose come "if" se la condizione fallisce, il modello non dovrebbe essere reso affatto. Quindi c'è molta flessibilità di cui ho bisogno per permetterti qui.

Pensieri?

    
posta mpen 11.01.2011 - 20:49
fonte

1 risposta

1

Vorrei prendere in considerazione la creazione di un'interfaccia generica.

public interface ITemplateDirective
{
    void Execute(Dictionary<string, object> data, TextWriter writer);
}

Quindi puoi definire alcune direttive di base:

public sealed class IfTemplateDirective : ITemplateDirective
{
    public IfTemplateDirective(
        Func<string, bool> predicate, 
        string value, 
        BlockTemplateDirective block)
    {
        // ...
    }

    public void Execute(Dictionary<string, object> data, TextWriter writer)
    {
        if (_predicate(_value)) 
        {
            _block.Execute(data, writer);
        }
    }
}

Chiaramente questo è un po 'forzato ma è come vorrei iniziare ad avvicinarmi.

    
risposta data 11.01.2011 - 21:39
fonte

Leggi altre domande sui tag