Ruby on Rails
CustomizeErbTemplates

Never satisfied with a ‘simple’ templating language, i really wanted to be able to |VARIABLE| and have it translate to <%= @object.variable %>, since that is what is printed most often.

I also allowed [% ] as aliases of < %> (sometimes you want it to show up in a WYSIWYG editor).

And conditionals bothered me, so xif means cross-if. Cross meaning crosses the precedding line of text… These are all just handled as simple regexes on the code. The controller name to use for @article is guessed from the directory the source file is in.

Print this text maybe <% xif @article.title =~ /the/ %>

will translate to:


<% if @article.title =~ /the/ >Print this text maybe< end %>

On a similar note,

Add to /vendor/actionpack/lib/action_view/erb_template.rb

    def preprocess(template_path, html)
      #$stderr.puts "Template_path is #{template_path}"
      
      #figure out controller name
      if template_path =~ %r{([^/]+)/([^/]+)/?$}
        controller = $1
      end
      
      #guess if it needs an 's' or not?
      #controller << 's' if $2 =~ /list/
      
      html.gsub!('[%','<%')
      html.gsub!('%]','%>')
  
      html.gsub!('|end|', '<% end %>')
      
      #BUMMER: this matches {|a,b| } for ruby blocks. or do |a|.  any way to tell the difference?  require uppercase?  Sure...
      html.gsub!(/\|([^@\s][^\|a-z]+)\|/) { # |VAR|, that don't contain a @ (so add current object)
        name = $1; name.downcase! if name == name.upcase
        "<%= @#{controller}.#{name} %>"
      }
      
      html.gsub!(/\|([^\|a-z]{1,30})\|/) { # other |VAR|
        name = $1; name.downcase! if name == name.upcase
        "<%= #{name} %>"
      }
      
      #xif = cross-if
      #<% xif @article.syndicated %> -> wrap line in <% if %>
      html.gsub!(/^(.*?)<%=? xif (.*?)%>\s*$/) {
        "<% if #$2%> #$1<% end %>"
      }
      
      # has? = has_attribute if
      html.gsub!(/^(.*?)<%=? hif (.*?)%>\s*$/) {
        "<% if @#{controller}.has_attribute? '#$2' %>#$1<% end %>"
      }
      
      # dif? = defined if
      html.gsub!(/^(.*?)<%=? dif (.*?)%>\s*$/) {
        "<% if @#{controller}.#$2 %>#$1<% end %>"
      }
      
      #eif = empty if
      html.gsub!(/^(.*?)<%=? eif (.*?)%>\s*$/) {
        "<% if @#{controller}.#$2.empty? %>#$1<% end %>"
      }
      html
    end

Then change read_template_file to be:

 def read_template_file(template_path)
        preprocess template_path, IO.readlines(template_path).join
      end

And the first line of source_extract re-loads the file instead of using the source thats passed to it, so fix that:


def source_extract
source_code = source.split "\n"#IO.readlines(file_name)

Enjoy! :)

Questions: is
/vendor/actionpack/lib/action_view/erb_template.rb
supposed to go under your Rails application directory? Do the methods shown above go into a class? How is tis new code loaded by Rails?

category:Howto