Używanie układów w plikach HAML niezależnie od Rails

Moim celem końcowym jest stworzenie kilku statycznych plików HTML do przekazania innym ludziom.

Ale dla mojego obiegu pracy, chciałbym mieć HAML jako podstawowe pliki źródłowe. Robiąc to, mam nadzieję wyschnąć proces przynajmniej po mojej stronie.

Teraz mam wiele stron, które ostatecznie będą miały wspólny układ i zastanawiam się, jak włączyć układy.

Oto mój obecny kod:

./ align = "left" / rb

#!/usr/bin/env ruby

require 'rubygems'
require 'rake'
require 'haml'

FileList.new('./src/*.html.haml').each do |filename|
  if filename =~ /([^\/]+)\.haml$/
    File.open($1, 'w') do |f|
      f.write Haml::Engine.new(File.read(filename)).render
    end
  end
end

./ src / layout.html.haml

!!!
%html
  %head
    %title Yay
  %body
    = yield

./ src / homehtml.haml

= render :layout => 'header' do
  %p This is awesome

Teraz to najwyraźniej nie działa, ponieważ metoda render jest niezdefiniowana poza kontekstem Rails, ale mam nadzieję, że trafi w sedno tego, co próbuję zrobić.

Jakieś sugestie?
 36
Author: Steven Xu, 2011-05-25

2 answers

Mieszasz dwie różne cechy Railsów: partials (za pomocą render) i layouts (za pomocą yield).

Możesz dodać wersję rails-podobną do jednej (lub obu) z nich do programu Haml only.

Częściowe

W widoku rails, możesz użyć render :partial_name, aby spowodować, że plik _partial_name.html.haml będzie renderowany w tym miejscu w widoku zawierającym (w rzeczywistości Rails pozwala na użycie dowolnego wspieranego języka szablonów i znajdzie poprawne rozszerzenie nazwy pliku, ale będę trzymać się tylko Haml tutaj). Outside of Rails render nie jest dostępny, ale można go dość łatwo dodać.

Prosta metoda render po prostu znajdzie odpowiedni plik haml, wyrenderuje go i zwróci łańcuch html do włączenia do rodzica:

def render(partial)
  # assuming we want to keep the rails practice of prefixing file names
  # of partials with "_"
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render
end

Pierwszym argumentem Haml::Engine.render jest obiekt scope, którego możemy użyć do dodania metod dostępnych wewnątrz szablonu haml. Domyślnie to Object.new. W takim prostym przypadku możemy jednak zdefiniować metodę render na górze poziom, i będzie on dostępny w zakresie szablonu Haml. Po prostu umieścimy naszą metodę render w skrypcie przed wywołaniem do Haml::Engine.new(...).render i wywołamy ją w ten sposób w naszym szablonie:

!!!
%html
  %head
    %title Hello
  %body
    =render :the_partial

Teraz plik _the_partial.html.haml pojawi się renderowany w odpowiednim punkcie wyjścia.

Zmienne lokalne

Możemy pójść o krok dalej. Rails pozwala na przekazanie w haśle zmiennych lokalnych do częściowego. Haml zaakceptuje również hash zmiennych, które mają być przekazywane jako lokalne zmienne, jako drugi argument metody Haml render. Jeśli więc rozszerzymy naszą metodę renderowania, aby wyglądała następująco:]}
def render(partial, locals = {})
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render(Object.new, locals)
end

Możemy użyć części, która wygląda mniej więcej tak:

%p You passed in #{foo}

I wywołaj go z naszego szablonu przez:

%body
  =render :partial, :foo => "bar"

Który wyrenderuje

<body>
  <p>You passed in bar</p>
</body>

Layouty

W Rails możesz określić układ dla swoich widoków, tak aby wszystkie Twoje strony mogły współdzielić to samo nagłówek, obszar menu itp. Można to zrobić poprzez podanie pliku układu, w którym wywołujesz yield aby renderować rzeczywisty widok, o którym mowa. Layouty są nieco trudniejsze do dodania do haml, ale nadal można to zrobić.

Hamls render metoda również akceptuje blok, więc prostym rozwiązaniem byłoby renderowanie pliku układu i przekazanie bloku, który renderuje plik widoku:

Haml::Engine.new(File.read("layout.html.haml")).render do
  Haml::Engine.new(File.read("view.html.haml")).render
end

Dałoby to zawartość layout.html.haml renderowaną z zawartością view.html.haml renderowaną tam, gdzie plik układu zawierał =yield.

Content_for

Rails jest jednak nieco bardziej elastyczny. Pozwala na wielokrotne wywołanie yield w pliku układu, nazwanie określonego regionu w każdym przypadku i określenie zawartości, która ma być dodana w każdym regionie za pomocą metody content_for w widokach. Więc w pliku układu:

!!!
%html
  %head
    = yield :title
  %body
    =yield

I Twoim zdaniem:

-content_for :title do
  %title Hello
%p
  Here's a paragraph.

Sposób, w jaki Rails działa, polega na renderowaniu części widoku, przechowywaniu wszystkich różnych sekcji, a następnie renderowaniu układu, przechodząc przez blok, który zapewnia odpowiedni fragment, gdy yield jest wywoływany w układ. Możemy to replikować za pomocą małej klasy pomocniczej, aby zapewnić metodę content_for i śledzić renderowane kawałki dla każdego regionu:

class Regions  
  def initialize
    @regions_hash={}
  end

  def content_for(region, &blk)  
    @regions_hash[region] = capture_haml(&blk)
  end

  def [](region)
    @regions_hash[region]
  end
end

Tutaj używamy capture_haml metoda aby uzyskać renderowany haml bez przechodzenia bezpośrednio do wyjścia. Zauważ, że nie uchwyci to nienazwanej części widoku.

Możemy teraz użyć naszej klasy pomocniczej do renderowania końcowego wyjścia.

regions = Regions.new
unnamed = Haml::Engine.new(File.read("view_named.html.haml")).render(regions)

output = Haml::Engine.new(File.read("layout_named.html.haml")).render do |region|
  region ? regions[region] : unnamed
end

Teraz zmienna output zawiera ostateczne renderowane wyjście.

Zauważ, że kod tutaj nie zapewnia całej elastyczności, która jest zawarta w rails, ale mam nadzieję, że wystarczy, aby pokazać, od czego zacząć dostosowywanie Haml do Twoich potrzeb.

 75
Author: matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-20 20:44:30
content = Haml::Engine.new(content_haml).render(
  Object.new, 
  :local_var_1 => ..., 
  :local_var_2 => ...
)


Haml::Engine.new(layout_haml).render(Object.new, :content => content)

Układ.haml

!!!
%html
  %head
    %title
  %body
    = content

Możesz również użyć zmiennych instancji Object.new (zastąp znaczącym obiektem) w haml, jak sądzę.

 5
Author: Victor Moroz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-25 13:51:02