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) #puts [node.name, node.klass, signature].inspect 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(@method) end rubyless_render(@method, params) rescue RubyLess::NoMethodError => err parser_continue("#{err.error_message} #{err.method_with_arguments} for #{err.receiver_with_class}") 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) rubyless_expand RubyLess.translate(self, code) 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, 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, value.literal) else markup.append_dyn_param(key, "<%= #{value} %>") end end def get_attribute_or_eval(use_string_block = true) if attribute = @params[:attr] || @params[:date] code = "this.#{attribute}" elsif code = @params[:eval] || @params[:test] elsif text = @params[:text] code = "%Q{#{text}}" 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 private # Extract arguments from params def extract_from_params(*keys) res = [] keys.each do |key| next unless value = @params[key.to_sym] res << ":#{key} => #{RubyLess.translate_string(self, value)}" end res.empty? ? nil : res 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 raise "#{node.klass.class}" unless node.klass.kind_of?(Array) || node.klass.kind_of?(Class) if type = node_context_from_signature(signature) # Resolve self, @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 type = type[:class].call(self, signature) if type[:class].kind_of?(Proc) type.merge(:method => "#{node.name}.#{type[:method]}") elsif node && node.list_context? && type = safe_method_from(node.klass.first, signature, node) type = type[:class].call(self, signature) if type[:class].kind_of?(Proc) type.merge(:method => "#{node.name}.first.#{type[:method]}") elsif @rendering_block_owner && @blocks.first.kind_of?(String) && !added_options # Insert the block content into the method: