diff --git a/bin/jekyll b/bin/jekyll index d3deed29bc0..8eb6462e689 100755 --- a/bin/jekyll +++ b/bin/jekyll @@ -68,6 +68,10 @@ opts = OptionParser.new do |opts| options['haml'] = true end + opts.on("--erb", "Enable using ERB for posts and pages") do + options['erb'] = true + end + opts.on("--version", "Display current version") do puts "Jekyll " + Jekyll.version exit 0 diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index f2a12556cb2..1855437c234 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -41,13 +41,17 @@ def transform self.ext = ".html" # Actually rendered in do_layout. self.content = Haml::Engine.new(self.content, :attr_wrapper => %{"}) + when 'erb' + self.ext = ".html" + # Actually rendered in do_layout. + self.content = ERB.new(self.content) end end # Determine which formatting engine to use based on this convertible's # extension # - # Returns one of :textile, :markdown or :unknown + # Returns one of :textile, :markdown, :haml, :erb or :unknown def content_type case self.ext[1..-1] when /textile/i @@ -56,6 +60,8 @@ def content_type return 'markdown' when /haml/i return 'haml' + when /erb/i + return 'erb' end return 'unknown' end @@ -72,6 +78,24 @@ def render_haml_in_context(haml_engine, params={}) haml_engine.render(context) 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_erb_in_context(erb_engine, params={}) + context = erb_context(params) + context.extend(Jekyll::ERBHelpers) + context.extend(::Helpers) if defined?(::Helpers) + erb_engine.result(context.get_binding) + end + + def erb_context(params={}) + @context ||= OpenStruct.new + @context.merge! params + @context + end + # Add any necessary layouts to this convertible document # +layouts+ is a Hash of {"name" => "layout"} # +site_payload+ is the site payload hash @@ -88,6 +112,11 @@ def do_layout(payload, layouts) self.content = render_haml_in_context(self.content, :site => self.site, :page => ClosedStruct.new(payload["page"])) + elsif self.content_type == "erb" + self.transform + self.content = render_erb_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 @@ -106,6 +135,12 @@ def do_layout(payload, layouts) :site => ClosedStruct.new(payload["site"]), :page => ClosedStruct.new(payload["page"]), :content => payload["content"]) + elsif site.config['erb'] && layout.content.is_a?(ERB) + puts "processing erb layout #{layout.name}" + self.output = render_erb_in_context(layout.content, + :site => ClosedStruct.new(payload["site"]), + :page => ClosedStruct.new(payload["page"]), + :content => payload["content"]) else self.output = Liquid::Template.parse(layout.content).render(payload, info) end diff --git a/lib/jekyll/core_ext.rb b/lib/jekyll/core_ext.rb index 92b15c816ca..c51004dfe8d 100644 --- a/lib/jekyll/core_ext.rb +++ b/lib/jekyll/core_ext.rb @@ -22,6 +22,18 @@ def deep_merge(hash) end require 'ostruct' + +class OpenStruct + def merge!(params) + params.keys.each do |k| + self.send("#{k}=",params[k]) + end + end + def get_binding + binding + end +end + class ClosedStruct < OpenStruct def method_missing(symbol, *args) raise(NoMethodError, "undefined method `#{symbol}' for #{self}") diff --git a/lib/jekyll/erb_helpers.rb b/lib/jekyll/erb_helpers.rb new file mode 100644 index 00000000000..1355710c0be --- /dev/null +++ b/lib/jekyll/erb_helpers.rb @@ -0,0 +1,39 @@ +require 'cgi' + +module Jekyll + module ERBHelpers + def erb(path,params={}) + result="dunce" + @context||=OpenStruct.new({:site=>site,:page=>page}.merge(params[:locals]||{})) + @context.extend(Jekyll::ERBHelpers) + @context.extend(::Helpers) if defined?(::Helpers) + template=ERB.new(File.read(File.join(site.source,"_partials","#{path.to_s}.erb"))) + result=template.result(@context.get_binding) + result + end + + def content_for(key, &block) + + @old_content||="" + pos=@old_content.length + result=block.call(*args) + data=result[pos..-1] + @old_content=result + data + + + content_blocks[key] << data + end + + def yield_content(key, *args) + content_blocks[key].join + end + + private + + def content_blocks + @content_blocks ||= Hash.new {|h,k| h[k] = [] } + end + + end +end diff --git a/lib/jekyll/layout.rb b/lib/jekyll/layout.rb index 7bb2d1a58fa..ce40694406e 100644 --- a/lib/jekyll/layout.rb +++ b/lib/jekyll/layout.rb @@ -5,7 +5,7 @@ class Layout attr_accessor :site attr_accessor :ext - attr_accessor :data, :content + attr_accessor :data, :content, :name # Initialize a new Layout. # +site+ is the Site @@ -34,4 +34,4 @@ def process(name) end end -end \ No newline at end of file +end diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 78c2bb6cc1b..7342061058c 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -57,6 +57,15 @@ def setup puts 'You must have the haml gem installed first' end end + + + if self.config['erb'] + require 'erb' + require 'jekyll/erb_helpers' + helpers = File.join(source, '_helpers.rb') + require helpers if File.exist?(helpers) + puts 'Enabled ERB' + end if self.pygments_cache require 'fileutils' @@ -275,6 +284,7 @@ def post_attr_hash(post_attr) # "topics" => [] }} def site_payload {"site" => { + "source" => self.source, "time" => Time.now, "posts" => self.posts.sort { |a,b| b <=> a }, "categories" => post_attr_hash('categories'),