Skip to content

Instantly share code, notes, and snippets.

@josevalim
Created March 18, 2010 16:41
  • Star 6 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save josevalim/336544 to your computer and use it in GitHub Desktop.
Who needs HAML when you have YAML + ERB?
# = YERB
#
# Who needs HAML when you have YAML + ERB? ;)
#
# See example.yaml below for an example. You can run this code
# by cloning this gist and then `ruby _yerb.rb example.yaml`.
#
# Notice that you need Ruby 1.9 so the hash order is preserved.
# Obviously, this is just for fun. Definitely slow as hell.
#
require "erb"
require "yaml"
class YERB
DOCTYPES = {
:html => "<!DOCTYPE html>"
}
ID = /#([^\.#\(]+)/
CLASS = /\.([^\.#\(]+)/
ATTRIBUTES = /(\{.*\})/
def initialize(path)
@path = path
end
def result(*args)
yaml = evaluate(File.read(@path), *args)
to_document(YAML.load(yaml))
end
protected
def evaluate(content, *args)
ERB.new(content).result(*args)
end
def to_document(hash)
doctype = hash.keys.first.to_sym
output = ""
output << DOCTYPES[doctype].to_s
output << "\n"
output << to_tags(hash)
output
end
def to_tags(hash)
hash.map do |key, value|
key = key.dup
attributes = get_attributes(key)
get_id(key, attributes)
get_classes(key, attributes)
tag(key, attributes, get_contents(value))
end.join("\n")
end
def get_attributes(key)
attributes = nil
key.gsub!(ATTRIBUTES) do
attributes = eval($1)
nil
end
attributes || {}
end
def get_id(key, attributes)
key.gsub!(ID) do
attributes[:id] = $1
nil
end
end
def get_classes(key, attributes)
classes = []
match = key.gsub!(CLASS) do
classes << $1
nil
end
attributes[:class] = classes.join(" ") if match
end
def get_contents(value)
case value
when Hash
to_tags(value)
when Array
value.map { |i| get_contents(i) }.join("\n")
else
value.to_s
end
end
def tag(tag, attributes, content)
attributes = attributes.map { |k,v| "#{k}=#{v.to_s.inspect}" }.join(" ")
attributes = " #{attributes}" unless attributes.empty?
"<#{tag}#{attributes}>#{content}</#{tag}>"
end
end
puts YERB.new(ARGV.first).result if ARGV.first
html:
head:
title: YERB Example
body:
p#intro:
Yes, this is still valid YAML after the embedded ruby code is evaluated.
ul.cool_list:
<% 1.upto(10) do |i| %>
- li: <%= i %> item in the list
<% end %>
a{:href => "http://blog.plataformatec.com.br"}:
"Odd, isn't it?"
@alexeymuranov
Copy link

By the way, how to embed HAML in YAML, to have templates like filename.yaml.haml ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment