Library to Parse Erb Files

Library to parse ERB files

I eventually ended up solving this problem by using RLex, http://raa.ruby-lang.org/project/ruby-lex/, the ruby version of lex with the following grammer:


%{

#define NUM 257

#define OPTOK 258
#define IDENT 259
#define OPETOK 260
#define CLSTOK 261
#define CLTOK 262
#define FLOAT 263
#define FIXNUM 264
#define WORD 265
#define STRING_DOUBLE_QUOTE 266
#define STRING_SINGLE_QUOTE 267

#define TAG_START 268
#define TAG_END 269
#define TAG_SELF_CONTAINED 270
#define ERB_BLOCK_START 271
#define ERB_BLOCK_END 272
#define ERB_STRING_START 273
#define ERB_STRING_END 274
#define TAG_NO_TEXT_START 275
#define TAG_NO_TEXT_END 276
#define WHITE_SPACE 277
%}

digit [0-9]
blank [ ]
letter [A-Za-z]
name1 [A-Za-z_]
name2 [A-Za-z_0-9]
valid_tag_character [A-Za-z0-9"'=@_():/ ]
ignore_tags style|script
%%

{blank}+"\n" { return [ WHITE_SPACE, yytext ] }
"\n"{blank}+ { return [ WHITE_SPACE, yytext ] }
{blank}+"\n"{blank}+ { return [ WHITE_SPACE, yytext ] }

"\r" { return [ WHITE_SPACE, yytext ] }
"\n" { return[ yytext[0], yytext[0..0] ] };
"\t" { return[ yytext[0], yytext[0..0] ] };

^{blank}+ { return [ WHITE_SPACE, yytext ] }

{blank}+$ { return [ WHITE_SPACE, yytext ] };

"" { return [ TAG_NO_TEXT_START, yytext ] }
"" { return [ TAG_NO_TEXT_END, yytext ] }
"" { return [ TAG_SELF_CONTAINED, yytext ] }
"" { return [ TAG_SELF_CONTAINED, yytext ] }
"" { return [ TAG_START, yytext ] }
"" { return [ TAG_END, yytext ] }

"" { return [ ERB_BLOCK_END, yytext ] }
"" { return [ ERB_STRING_END, yytext ] }

{letter}+ { return [ WORD, yytext ] }

\".*\" { return [ STRING_DOUBLE_QUOTE, yytext ] }
'.*' { return [ STRING_SINGLE_QUOTE, yytext ] }
. { return [ yytext[0], yytext[0..0] ] }

%%

This is not a complete grammer but for my purposes, locating and re-emitting text, it worked. I combined that grammer with this small piece of code:


text_handler = MakeYourOwnCallbackHandler.new

l = Erblex.new
l.yyin = File.open(file_name, "r")

loop do
a,v = l.yylex
break if a == 0

if( a < WORD )
text_handler.character( v.to_s, a )
else
case a
when WORD
text_handler.text( v.to_s )
when TAG_START
text_handler.start_tag( v.to_s )
when TAG_END
text_handler.end_tag( v.to_s )
when WHITESPACE
text_handler.white_space( v.to_s )
when ERB_BLOCK_START
text_handler.erb_block_start( v.to_s )
when ERB_BLOCK_END
text_handler.erb_block_end( v.to_s )
when ERB_STRING_START
text_handler.erb_string_start( v.to_s )
when ERB_STRING_END
self.text_handler.erb_string_end( v.to_s )
when TAG_NO_TEXT_START
text_handler.ignorable_tag_start( v.to_s )
when TAG_NO_TEXT_END
text_handler.ignorable_tag_end( v.to_s )
when STRING_DOUBLE_QUOTE
text_handler.string_double_quote( v.to_s )
when STRING_SINGLE_QUOTE
text_handler.string_single_quote( v.to_s )
when TAG_SELF_CONTAINED
text_handler.tag_self_contained( v.to_s )
end
end
end

Including one erb file into another

ERB templates can be nested by evaluating the sub-template from within <%= %> of the main template.

<%= ERB.new(sub_template_content).result(binding) %>

For example:

require "erb"

class Page
def initialize title, color
@title = title
@color = color
end

def render path
content = File.read(File.expand_path(path))
t = ERB.new(content)
t.result(binding)
end
end

page = Page.new("Home", "#CCCCCC")
puts page.render("home.html.erb")

home.html.erb:

<title><%= @title %></title>
<head>
<style type="text/css">
<%= render "home.css.erb" %>
</style>
</head>

home.css.erb:

body {
background-color: <%= @color %>;
}

produces:

<title>Home</title>
<head>
<style type="text/css">
body {
background-color: #CCCCCC;
}
</style>
</head>

ERB like library for C#

Have a look at TemplateMachine, I haven't tested it, but it seems to be a bit ERB-like.

Stack trace showing ERB syntax error. Is the problem with app code or ERB library?

The stack trace shows lines from ERb because ERb code is the one that is executing.

While the issue could theoretically be in either ERb itself or your template, it is much more likely that the issue is in your template given that ERb is used by thousands of developers and applications daily.

Parsing process for views in rails

You were right to think that the view code would be read from top to bottom and processed in that way. But there is a problem with this approach. ERB is a template engine/library, and for a template engine to be fast it has to work intelligently.

The process of rendering the action goes something like this:

  • Request is passed to the controller
  • Before and around filters are ran
  • Specified action runs and now Rails know which file to render
  • ERB code is picked from the ERB file ignoring all the HTML as Rails does not know anything to do with it
  • ERB code is processed in an orderly fashion. For ex:

    <%= render 'my_header' %>
    This is some HTML
    <%= render 'my_footer' %>

    In this scenario the file _my_header.html.erb would be processed and injected first and then _my_footer.html.erb would be processed and injected. ERB tags are resolved from top to bottom.

  • This whole file is injected into the layout file in place of <%= yield %>
  • After filters are ran and around filters are closed
  • The data is sent to the client

I hope this clears all your questions about the ERB library.

Parsing an xml doc with % % tags in ruby

Well, provided that you want the actual Ruby code itself, your problem is not with the parser, but the fact that your XML is malformed.

I'm still assuming your XML looks something like this:

<parent>
<node>
<% some code here! %>
</node>
</parent>

If that is indeed the case, the contents of the node node (heh) should actually be a CDATA section. So it should look like this:

<node><![CDATA[
<% some code here! %>
]]></node>

If you do this, REXML will be able to properly parse the XML file, and return the contents of node, which will include the erb tags.

If you do not have control over the generation of the XML, you could, as a stop-gap fix, just (assuming that any given node that contains ERB only contains ERB) do a file wide search and replace for the start and end code tags, and appropriately append/prepend the CDATA markup. You could easily automate this in your language of choice, there's plenty of examples here on SO.

How to template like ERB in Python?

Mako allows to write a regular block of Python code, like this

this is a template
<%
x = db.get_resource('foo')
y = [z.element for z in x if x.frobnizzle==5]
%>
% for elem in y:
element: ${elem}
% endfor

http://docs.makotemplates.org/en/latest/syntax.html#python-blocks

Parametrized nested erb components in Rails

Okay, I found the way. We can do this with render function. I created file named _my_element.erb which looks like this:

<div>
some text
<%= myFirstParam + mySecondParam %>
some another text
</div>

It's located in views folder, which seems to be important.

Next in my_body file I inserted:

<%= render partial: "my_element.erb",
locals: {myFirstParam: 1, mySecondParam: 2} %>

For some reason name of file should begins with _ char, while path in partial parameter should't include it.

But after all, that works.



Related Topics



Leave a reply



Submit