lib/malt/engines/builder.rb in malt-0.3.0 vs lib/malt/engines/builder.rb in malt-0.4.0
- old
+ new
@@ -6,65 +6,126 @@
#
# http://builder.rubyforge.org/
#
class Builder < Abstract
- default :builder
+ default :builder, :rbml
#
- #def intermediate(params)
- #end
+ def render(params={}, &content)
+ into = parameters(params, :to) || :html
- #
- def render(params, &yld)
- into = params[:to]
case into
- when :html, nil
- render_html(params, &yld)
+ when :xml, :html, :xhtml
+ prepare_engine(params, &content) #.target!
else
- super(params, &yld)
+ super(params, &content)
end
end
- # TODO: Do we need a #make_ivar(data, &yld) method to make data into
- # instance variables for some templates like this one?
- def render_html(params={}, &yld)
- text = params[:text]
- file = params[:file]
- data = params[:data]
+ #private
- data = make_hash(data, &yld)
- builder = ::Builder::XmlMarkup.new(engine_options(params))
- data.each{ |k,v| builder.instance_eval("@#{k} = v") }
- builder.instance_eval(text, file)
+ # Prepare engine for rendering.
+ def prepare_engine(params={}, &content)
+ prefix = parameters(params, :prefix)
+
+ if prefix
+ prepare_engine_prefix(params, &content)
+ else
+ prepare_engine_scope(params, &content)
+ end
end
- private
+ # TODO: Can Builder be cached?
- # Load Erector library if not already loaded.
- def initialize_engine
+ #
+ def create_engine(params={})
+ opts = engine_options(params)
+
+ #cached(opts) do
+ ::Builder::XmlMarkup.new(opts)
+ #end
+ end
+
+ #
+ def prepare_engine_prefix(params, &content)
+ prefix, text, file, scope, locals = parameters(params, :prefix, :text, :file, :scope, :locals)
+
+ bind = make_binding(scope, locals, &content)
+
+ #scope, locals = split_data(data)
+
+ #scope ||= Object.new
+ #locals ||= {}
+
+ engine = create_engine(params)
+
+ code = %{
+ lambda do |#{prefix}|
+ #{text}
+ end
+ }
+
+ eval(code, bind, file || '(builder)').call(engine)
+ end
+
+ # TODO: woud rather set instance variable via #instance_variable_set
+ # but it is not defined.
+
+ #
+ def prepare_engine_scope(params, &content)
+ text, file, scope, locals = parameters(params, :text, :file, :scope, :locals)
+
+ scope, locals = make_external(scope, locals, &content)
+
+ engine = create_engine
+
+ locals.each do |k,v|
+ next if k.to_sym == :target
+ engine.instance_eval("@#{k} = v")
+ end
+
+ unless scope.respond_to?(:to_struct)
+ scope.instance_variables.each do |k|
+ next if k == "@target"
+ v = scope.instance_variable_get(k)
+ engine.instance_eval("#{k} = v")
+ end
+ end
+
+ engine.instance_eval(text, file || '(builder)')
+
+ engine.target!
+ end
+
+ private
+
+ # Load Builder library if not already loaded.
+ def require_engine
return if defined? ::Builder
require_library 'builder'
+
+ # Inexplicably Ruby 1.8 acts like the p method is present
+ # if undef_method is not used, but acts like it isn't if
+ # undef_method is used (raising an error).
+ ::Builder::XmlBase.class_eval do
+ undef_method :p rescue nil
+ end
end
+ #
# :target=>target_object: Object receiving the markup. target_object must
# respond to the <<(a_string) operator and return itself.
# The default target is a plain string target.
#
# :indent=>indentation: Number of spaces used for indentation. The default
# is no indentation and no line breaks.
#
# :margin=>initial_indentation_level: Amount of initial indentation
# (specified in levels, not spaces).
- def engine_options(params)
- target = params[:target] || settings[:target]
- indent = params[:indent] || settings[:indent]
- margin = params[:margin] || settings[:margin]
- opts = {}
- opts[:target] = target if target
- opts[:indent] = indent if indent
- opts[:margin] = margin if margin
- opts
+ #
+ def engine_option_names
+ [:target, :indent, :margin]
end
end
end