WL – Jazyk pro psaní webových aplikací

Začínáme s WebLou

WebLa, či jednoduše WL, je specializovaný programovací jazyk a framework pro tvorbu webů.

Usnadňuje:

Jak WL funguje?

Webová aplikace se skládá z řídících objektů obsahujících řídící metody. Řídící metody mají za úkol zpracovat HTTP požadavek pro jimi určené URL.

Takto vypadá klasická aplikace, ze které vás jazyk WL pozdraví:

// Já aplikace sestávám z jednoho řídícího objektu s názvem 'app'
control app
{
  // Ošetřuji požadavek GET na libovolnou adresu v prohlížeči ('.*' je regulární výraz)
  GET ".*"
  {
    // Tisknu do výstupu pozdrav
    prn("Ahoj světe!");

    // a končím!
    exit();
  }
}

S výstupem jednoduchého textu si vystačí malokterá webová aplikace. Většina z nich bude chtít vracet HTML kód. WL pro tento účel obsahuje koncept šablon HTML stránek. Výsledná HTML stránka vzniká kombinací šablony a dat, které jí připraví řídící funkce.

Šablony stránek mají svůj vlastní jazyk, který usnadňuje jejich tvorbu a vyplňování daty. Nepracuje se přímo s HTML kódem, protože to má svá omezení a není to pohodlné.

Takto zařídíte, aby vás aplikace pozdravila pomocí HTML stránky:

// Já aplikace dělám to samé co kolegyně výše...
control app
{
  GET ".*"
  {
    // ...s tím rozdílem, že si připravím data pro šablonu
    local data = {
      message: "Ahoj světe! Už umím s HTML!"
    };

    // ...a vracím světu HTML stránku!
    return new page greeter(data);
  }
}

// Já šablona jsem odvozená od jiné šablony 'wl_base', která mi usnaďňuje běžné
// činnosti, jako vkládání CSS a JS souborů, nastavoání titulku stránky, meta
// informací, ikonky webu,...
page greeter wl_base
{
  // Nastavím si výchozí titulek stránky
  title = "Zdravící stránka"
  // a výchozí zprávu.
  message = "zapoměli mě vyplnit"

  // Každá šablona sestavuje výslednou stránku z fragmentů. Následuje definice
  // fragmentu nazvaného 'body', který obsahuje nadpis (h1) a odstavec (p). Do
  // nadpisu se doplní hodnota proměnné 'title' a do odstavce hodnota 'message'.
  //
  // Celý fragment 'body' se nakonec vloží do těla HTML stránky.
  body
  {
    h1 {:title}
    p {:message}
  }
}

// Zvědavější z vás budou asi koumat, co před nimi skrývá šablona 'wl_base'.
// Následující mini-implementace ukazuje její části využívané šablonou 'greeter'.
page wl_base
{
  // Jsem stránka typu HTML5, mohu být také XHTML stránka
  DOCTYPE = "html"

  // Výchozí hodnota titulku
  title = "WL"

  // Každá šablona sestavuje výslednou stránku z fragmentů. Fragment s názvem
  // 'page' je povinný a reprezentuje celou HTML stránku.
  page
  {
    html
    {
      head
      {
        // Titulek HTML stránky nastavíme z proměnné title
        title {:title}
      }
      body
      {
        // Do těla stránky vložíme obsah fragmentu 'body', který budou moci definovat
        // šablony odvozené od wl_base.
        #include body
      }
    }
  }
}

Aplikace už vás zdraví. Jak jí ale s pomocí WL pozdravíte vy? Jinak řečeno, jak s pomocí WL vytvoříte formulář a zpracujete odpověď uživatele na pozdrav?

Po odstranění komentářů a pár zjednodušeních nyní máme tento počáteční kód:

control app
{
  GET ".*"
  {
    return new page greeter({
      message: "Ahoj světe! Už umím s HTML!"
    });
  }
}

page greeter wl_base
{
  title = "Zdravící stránka"
  message = "zapoměli mě vyplnit"

  body
  {
    h1 {:title}
    p {:message}
  }
}

Chceme doplnit formulář a do něj vstupní pole, jeden výběrový box s naší náladou a jeden textový vstup pro naši odpověď na pozdrav.

// [...]

page greeter wl_base
{
  title = "Zdravící stránka"
  message = "zapoměli mě vyplnit"

  body
  {
    h1 {:title}
    p {:message}

    // Takto může vypadat kód formuláře. V této podobě je to jen přepis stejně
    // strukturovaného HTML kódu.
    p {"Jak se máš?"}
    form
    {
      // Parametrem atributu může být libovolný výraz. Zde je to spojení
      // absolutní cesty k aplikaci a cesty v rámci aplikce k řídící metodě
      // 'response' (např.: "/webla/" + "response")
      @action request.root() + "response"
      @method "post"

      select
      {
        @name "mood"
        option {"Mám se super"}
        option {"Jde to"}
        option {"Nic moc"}
      }

      input
      {
        @name "response"
        @placeholder "pozdravte nás"
      }
    }
  }
}

Moc šablonového systému WL spočívá ve třech mechanismech, které umožňují programátorovi se neopakovat (DRY) při vytváření šablon stránek. Opakování se při programování není matka moudrosti.

Dva z těchto konceptů už byly demonstrovány výše. Byly to odvozování nových šablon od již existujících a související dělení stránky do fragmentů. Tento mechanismus umožňuje například vytvořit rámec stránky s hlavičkou a patičkou a v odvozených šablonách implementovat různý obsah.

Posledním DRY mechanismem jsou makra. Níže ukáži jeden ze způsobů, kterým lze výše uvedený formulář zjednodušit pomocí maker.

// [...]

page greeter wl_base
{
  title = "Zdravící stránka"
  message = "zapoměli mě vyplnit"

  body
  {
    h1 {:title}
    p {:message}

    p {"Jak se máš?"}

    // Takto může vypadat kód formuláře využívajícího makra.
    #macro form("response")
    {
      #macro select("mood", ["Mám se super", "Jde to", "Nic moc"])
      #macro input("name", {
        placeholder: "Bla bla"
      })
    }
  }

  // Definice jednotlivých maker:

  macro form(path, method)
  {
    form
    {
      @action request.root() + (path || request.path())
      @method method || "post"

      #slot default
    }
  }

  macro select(name, options)
  {
    select
    {
      @name name

      #repeat o in options
      {
        option {:o}
      }
    }
  }

  macro input(name, config)
  {
    input
    {
      @name name
      #cond config && config.placeholder
      {
        @placeholder config.placeholder
      }
    }
  }
}

Využití maker je výborné, máte-li více formulářů, s mnoha poli a chcete aby jejich markup byl definovaný na jednom místě a šel centrálně měnit a upravovat.

Další výhod tkví v tom, že v místě jejich využití je kód šablony přehlednější.

Makra mohou skrývat různé chytricismy, které usnadní vytváření fomulářových prvků, vyplňování výchozími hodnotami, či hodnotami z databáze, zobrazování chybových zpráv, atd.

Díky slotům je lze využít in na centrální definici kontejnerů pro další prvky. Ukázkou byl kontejner formuláře definovaný pomocí makra.

Například můžete mít kontejner, který vrací různý markup, podle toho ve kterém prohlížeči ho uživatel sleduje. Můžete tak snadno podporovat kulaté rohy v starých prohlížečích a zároveň nenafukovat markup pro moderní prohlížeče, které kulaté rohy umí stylovat skrze CSS.