require 'markaby/rails/rails_builder'
module ActionView # :nodoc:
class Base # :nodoc:
def render_template(template_extension, template, file_path = nil, local_assigns = {})
if handler = @@template_handlers[template_extension]
template ||= read_template_file(file_path, template_extension)
handler.new(self).render(template, local_assigns, file_path)
else
compile_and_render_template(template_extension, template, file_path, local_assigns)
end
end
end
end
module Markaby
module Rails
class Template
def self.builder_class=(builder)
@@builder_class = builder
end
def self.builder_class
@@builder_class ||= Builder
end
attr_accessor :source, :path
def initialize(source)
@source = source.to_s
end
def render(*args)
output = self.class.builder_class.new(*args)
if path
output.instance_eval source, path
else
output.instance_eval source
end
output.to_s
end
end
# Markaby helpers for Rails.
module ActionControllerHelpers
# Returns a string of HTML built from the attached +block+. Any +options+ are
# passed into the render method.
#
# Use this method in your controllers to output Markaby directly from inside.
def render_markaby(options = {}, &block)
render options.merge({ :text => Builder.new(options[:locals], self, &block).to_s })
end
end
class ActionViewTemplateHandler # :nodoc:
def initialize(action_view)
@action_view = action_view
end
def render(template, local_assigns, file_path)
template = Template.new(template)
template.path = file_path
template.render(@action_view.assigns.merge(local_assigns), @action_view)
end
end
class Builder < RailsBuilder # :nodoc:
def initialize(*args, &block)
super *args, &block
@assigns.each { |k, v| @helpers.instance_variable_set("@#{k}", v) }
end
def flash(*args)
@helpers.controller.send(:flash, *args)
end
# Emulate ERB to satisfy helpers like form_for.
def _erbout
@_erbout ||= FauxErbout.new(self)
end
# Content_for will store the given block in an instance variable for later use
# in another template or in the layout.
#
# The name of the instance variable is content_for_ to stay consistent
# with @content_for_layout which is used by ActionView's layouts.
#
# Example:
#
# content_for("header") do
# h1 "Half Shark and Half Lion"
# end
#
# If used several times, the variable will contain all the parts concatenated.
def content_for(name, &block)
@helpers.assigns["content_for_#{name}"] =
eval("@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)")
end
end
Template.builder_class = Builder
class FauxErbout < ::Builder::BlankSlate # :nodoc:
def initialize(builder)
@builder = builder
end
def nil? # see ActionView::Helpers::CaptureHelper#capture
true
end
def method_missing(*args, &block)
@builder.send *args, &block
end
end
end
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
ActionView::Template
else
ActionView::Base
end.register_template_handler(:mab, Markaby::Rails::ActionViewTemplateHandler)
end