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