Include ERB delimiters inside a row in an ERB block

I am working on a style that displays code as well as output. Currently, it is structured in such a way that the code should be described only once and is displayed both in its source and in interpreted versions, for example:

<% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR <div> #{ image_tag 'image.png' } </div> PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR %> <%= raw code %> <%= content_tag :pre, code, class: "prettyprint linenums" %> 

This is great and fairly easy to maintain. The problem occurs with rail assistants, for example, image_tag in the example above. The example view correctly displays the image in a div, and the corresponding HTML displays the image in the sample code. In this case, the corresponding HTML code contains an anchor tag - the results of the image_tag method, and not the call itself.

I would prefer code examples to display helper methods rather than their results. I can do this work by specifying sample code in a file, and either rendering or reading the file. I would prefer to do this work by specifying the code in a variable as above, but I cannot get the ERB delimiter to work inside a string inside an erb block. Even the simplest case <% foo = '<%= bar %>' %> does not work at all. I tried playing with syntax (e.g. <%% %%> and <%% %%> ) using data from official documentation without much success.

The only information I could find on this was here using <%= "<" + "%=" %> link_to <%= image.css_tag.humanize %> <%= "%" + ">" %> %> , which does not work in this use case (if at all).

So, is there a way to specify a string containing the trailing ERB delimiter ( %> ) in the ERB string, or am I stuck using a slightly clunkier file reading method? Thanks!

Edit:

What I would like to get is a working version of this:

 <%# Idealized code - does not work %> <% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR <div> <% image_tag 'image.png' %> </div> PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR %> 

So, <%= raw code %> will (continue) output:

 <div> <img src="/images/image.png" alt="Image" /> </div> 

And <%= content_tag :pre, code, class: "prettyprint linenums" %> outputs:

 <pre class="prettyprint linenums"> <div> <% image_tag 'image.png' %> </div> </pre> 

Instead of what it is currently doing when using a variable that:

 <pre class="prettyprint linenums"> <div> <img src="/images/image.png" alt="Image" /> </div> </pre> 

I want users to be able to copy the sample code and paste it into a new view, without having to translate the HTML back into the helpers that produce them. I think I basically need an alternative ERB delimiter, just as ' and " (or even %q{} ) are different for strings. It seems that although the final ERB delimiter occurs inside a string, it is actually treated as the end of the block. The simplest the case <% foo = '<%= bar %>' %> somewhat demonstrates what I want to do. In the generator you can use <% foo = '<%%= bar %>' %> (or something like that ), to say that it is not processed like ERB right there and there. All this works fine when reading from a file or even in a pure rb file (for example, an assistant), but It makes sense to insert him into submission, as it should be easily manipulated by our designers.

+4
source share
1 answer

If I understand you correctly, your real problem is that heredocs behave like double quotes with respect to interpolation. So, all you need is a quoting mechanism that behaves like single quotes. Ruby has many mechanisms for quoting strings, in particular we have %q{...} :

 <% code = %q{ <div> #{ image_tag 'image.png' } </div> } %> 

You can use other delimiters if you want: %q|...| , %q(...) , etc. There is still a change in course, but at least you don't need to worry about problems with interpolation.

If you really want to use heredoc, you can specify a heredoc terminator with quotes , and the corresponding citation style will apply to the content:

 <% code = <<'PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR' <div> #{ image_tag 'image.png' } </div> PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR %> 

The single quotation marks in <<'PLACE...' indicate that uniform quotation rules (i.e. interpolation) apply to the heredoc content.


Of course, none of these materials will work with embedded ERB as follows:

 <% code = %q{ <div> <% ... %> </div> } %> 

because the ERB parser will see the first %> as a closing delimiter for the outer part <% code... Don't be afraid, I think I have a plan that will work without involving gross hacks or too much work.

Some preliminary :

Using the above, you can add your own template format, which is an ERB with a different separator, and you can use Rails in this new format to process your β€œspecial” sections before normal ERB processing can mess things up.

First you need to connect the Tilt. If you look at lib/tilt/erb.rb in your Tilt installation, you will see the Erubis stuff in Tilt::ErubisTemplate below. You must have a subclass of Tilt::ErubisTemplate and provide an override of prepare that adds, say, the option :pattern => '<!--% %-->' Tilt::ErubisTemplate :pattern => '<!--% %-->' , and discards the superclass. Then register this with Tilt and Sprockets in the Rails initializer with something like this:

 Tilt.register(Your::Template::Subclass, 'klerb') # "kl" for "kludge" :) Rails.application.assets.register_engine('.klerb', Your::Template::Subclass) 

Your application should now be able to process .klerb files using <!--% ... %--> as template separators. And you can also link your klerb to erb using names like pancakes.html.erb.klerb and the file will go through klerb before ERB; this means that such templates (in a file named whatever.html.erb.klerb ):

 <!--% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR <div> <% image_tag 'image.png' %> </div> PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR %--> <!--%= "code = escape_the_erb_as_needed(%q{#{code}})" %--> <% do_normal_erb_stuff %> 

will do the right thing.

To implement the escape_the_erb_as_needed function escape_the_erb_as_needed you need a helper; a little experimentation should help you figure out what you need to run away and how.

All that may seem a bit complicated, but it is really quite straightforward. I added custom template processing steps using Tilt and Sprockets, and in the end it turned out to be pretty simple; figuring out what simple things needed to be done, but I already did this job for you:

  • Tilt::Template , you get this based on Tilt::ErubisTemplate .
  • Register with Tilt by calling Tilt.register .
  • Register using the asterisks by calling Rails.application.assets.register_engine .
  • ...
  • Profit
+5
source

Source: https://habr.com/ru/post/1444487/


All Articles