require 'rubyless' module Zafu module Process module RubyLessProcessing include RubyLess def self.included(base) base.process_unknown :rubyless_eval base.class_eval do def do_method(sym) super rescue RubyLess::Error => err parser_error(err.message) end end end # Actual method resolution. The lookup first starts in the current helper. If nothing is found there, it # searches inside a 'helpers' module and finally looks into the current node_context. # If nothing is found at this stage, we prepend the method with the current node and start over again. def safe_method_type(signature, receiver = nil) super || get_method_type(signature, false) end # Resolve unknown methods by using RubyLess in the current compilation context (the # translate method in RubyLess will call 'safe_method_type' in this module). def rubyless_eval(params = @params) if @method =~ /^([A-Z]\w+?)\?$/ return rubyless_class_scope($1) end rubyless_render(@method, params) rescue RubyLess::NoMethodError => err parser_continue("#{err.error_message} #{err.method_with_arguments} (#{node.klass} context)") rescue RubyLess::Error => err parser_continue(err.message) end # Print documentation on the current node type. def r_m if @params[:helper] == 'true' klass = helper.class else klass = node.klass end out "
<%= @erb.gsub('<','<').gsub('>','>') %>" # end def rubyless_render(method, params) # We need to set this here because we cannot pass options to RubyLess or get them back # when we evaluate the method to see if we can use blocks as arguments. @rendering_block_owner = true code = method_with_arguments(method, params) # It is strange that we need to freeze code... But if we don't, we # get double ##{} on some systems (Linux). rubyless_expand RubyLess.translate(self, code.freeze) ensure @rendering_block_owner = false end def set_markup_attr(markup, key, value) value = value.kind_of?(RubyLess::TypedString) ? value : RubyLess.translate_string(self, value) if value.literal markup.set_param(key, form_quote(value.literal)) else markup.set_dyn_param(key, "<%= #{value} %>") end end def append_markup_attr(markup, key, value) value = RubyLess.translate_string(self, value) if value.literal markup.append_param(key, form_quote(value.literal)) else markup.append_dyn_param(key, "<%= #{value} %>") end end def get_attribute_or_eval(use_string_block = true) if @params[:date] && method != 'link' return parser_continue("'date' parameter is deprecated. Please use 'attr' or 'eval'.") elsif attribute = @params[:attr] code = "this.#{attribute}" elsif code = @params[:eval] || @params[:test] elsif code = @params[:param] code = "params[:#{code}]" elsif text = @params[:text] code = "%Q{#{text}}" elsif text = @params[:t] code = "t(%Q{#{text}})" # elsif var = @params[:var] # if code = get_context_var('set_var', var) # return code # else # return parser_continue("Var #{var.inspect} not declared.") # end elsif use_string_block && @blocks.size == 1 && @blocks.first.kind_of?(String) return RubyLess::TypedString.new(@blocks.first.inspect, :class => String, :literal => @blocks.first) else return parser_continue("Missing attribute/eval parameter") end RubyLess.translate(self, code) rescue RubyLess::Error => err return parser_continue(err.message, code) end # Pass default values as parameters in @context as :param_XXXX def r_default cont = {} @params.each do |k, v| cont[:"params_#{k}"] = v end expand_with cont end private # Extract arguments from params (evaluates params as RubyLess strings). def extract_from_params(*keys) res = [] keys.each do |key| next unless value = param(key.to_sym) res << ":#{key} => #{RubyLess.translate_string(self, value)}" end res.empty? ? nil : res end def param(key, default = nil) @params[key] || @context[:"params_#{key}"] || default end # Method resolution. The first matching method is returned. Order of evaluation is # 1. find node_context (@page, @image, self) # 2. set var (set_xxx = '...') # 3. template helper methods # 4. contextual node methods (var1.xxx) # 5. contextual first node of list method ([...].first.xxx) # 6. append block as argument (restart 1-5 with xxx(block_string)) def get_method_type(signature, added_options = false) node = self.node if type = node_context_from_signature(signature) # Resolve this, @page, @node type elsif type = get_var_from_signature(signature) # Resolved stored set_xxx='something' in context. type elsif type = safe_method_from(helper, signature) # Resolve template helper methods type elsif helper.respond_to?(:helpers) && type = safe_method_from(helper.helpers, signature) # Resolve by looking at the included helpers type elsif node && !node.list_context? && type = safe_method_from(node.klass, signature, node) # not a list_contex # Resolve node context methods: xxx.foo, xxx.bar # All direct methods from nodes should be html escaped: type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc) type.merge(:receiver => RubyLess::TypedString.new(node.name, :class => node.klass, :h => true)) elsif node && node.list_context? && type = safe_method_from(Array, signature, node) # FIXME: why do we need this here ? Remove with related code in zafu_safe_definitions ? type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc) type.merge(:receiver => RubyLess::TypedString.new(node.name, :class => Array, :elem => node.klass.first)) elsif node && node.list_context? && type = safe_method_from(node.klass.first, signature, node) type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc) type.merge(:receiver => RubyLess::TypedString.new("#{node.name}.first", :class => node.klass.first, :h => true)) elsif @rendering_block_owner && @blocks.first.kind_of?(String) && !added_options # Insert the block content into the method: