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?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 Hamlrender
. 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.
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ę.
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