Skip to content

Commit

Permalink
Allow _helpers.rb in blogs to provide custom Haml helpers. Document t…
Browse files Browse the repository at this point in the history
…he provided ones. DRY up Haml rendering. Don't use OpenStruct for Haml context since it won't complain about methods that don't exist.
  • Loading branch information
henrik committed Apr 16, 2009
1 parent 15f0383 commit b9dea95
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 11 deletions.
12 changes: 12 additions & 0 deletions README.textile
Expand Up @@ -177,6 +177,18 @@ converted. Layouts don't need to.

Haml content is intentionally not filtered, so you can use any Ruby code.

If you want to define methods you can call from your Haml files, create
a _helpers.rb file in the root of your blog and put the methods there,
inside a module named Helpers.

Jekyll provides some helpers out of the box:

h(string)
HTML entity-escapes the input string.

link_to(text, url)
Creates a link to the URL with the linked text (or markup).

h3. Local Server

When previewing complex sites locally, simply opening the site in a web
Expand Down
27 changes: 18 additions & 9 deletions lib/jekyll/convertible.rb
Expand Up @@ -59,6 +59,18 @@ def content_type
end
return 'unknown'
end

# Sets up a context for Haml and renders in it. The context has accessors
# matching the passed-in hash, e.g. "site", "page" and "content", and has
# helper modules mixed in.
#
# Returns String.
def render_haml_in_context(haml_engine, params={})
context = ClosedStruct.new(params)
context.extend(HamlHelpers)
context.extend(::Helpers) if defined?(::Helpers)
haml_engine.render(context)
end

# Add any necessary layouts to this convertible document
# +layouts+ is a Hash of {"name" => "layout"}
Expand All @@ -72,11 +84,10 @@ def do_layout(payload, layouts)
payload["content_type"] = self.content_type

if self.content_type == "haml"
context = OpenStruct.new(:site => self.site, :page => OpenStruct.new(payload["page"]))
context.extend(HamlHelpers)

self.transform
self.content = self.content.render(context)
self.content = render_haml_in_context(self.content,
:site => self.site,
:page => ClosedStruct.new(payload["page"]))
else
self.content = Liquid::Template.parse(self.content).render(payload, info)
self.transform
Expand All @@ -91,12 +102,10 @@ def do_layout(payload, layouts)
payload = payload.deep_merge({"content" => self.output, "page" => layout.data})

if site.config['haml'] && layout.content.is_a?(Haml::Engine)
context = OpenStruct.new(
:page => OpenStruct.new(payload["page"]),
:site => OpenStruct.new(payload["site"]),
self.output = render_haml_in_context(layout.content,
:site => ClosedStruct.new(payload["site"]),
:page => ClosedStruct.new(payload["page"]),
:content => payload["content"])
context.extend(HamlHelpers)
self.output = layout.content.render(context)
else
self.output = Liquid::Template.parse(layout.content).render(payload, info)
end
Expand Down
9 changes: 8 additions & 1 deletion lib/jekyll/core_ext.rb
Expand Up @@ -19,4 +19,11 @@ def deep_merge(hash)

target
end
end
end

require 'ostruct'
class ClosedStruct < OpenStruct
def method_missing(symbol, *args)
@table.has_key?(symbol) ? super : raise(NoMethodError, "undefined method `#{symbol}' for #{self}")
end
end
3 changes: 2 additions & 1 deletion lib/jekyll/site.rb
Expand Up @@ -50,8 +50,9 @@ def setup
if self.config['haml']
begin
require 'haml'
require 'ostruct'
require 'jekyll/haml_helpers'
helpers = File.join(source, '_helpers.rb')
require helpers if File.exist?(helpers)
puts 'Enabled Haml'
rescue LoadError
puts 'You must have the haml gem installed first'
Expand Down

0 comments on commit b9dea95

Please sign in to comment.