Ruby erb template is removing too much whitespace - ruby

I have the following line in my erb template:
SetEnv <%= name %> <%= value %>
The output from this line looks like this...
SetEnv SomeNameSomeValue
There is no whitespace between the name and value items.
I want it to output this:
SetEnv SomeName SomeValue
I've found lots of articles explaining how to get erb files to strip unwanted whitespace, but I want the whitespace. How do I get the whitespace to stay in place?

How about <%= "#{name} #{value}" %>?

Related

How to replace words inside template placeholders

I'm trying to write a regular expression to replace <%= Name %> with "Some Person".
I'm using a regex because I want to modify it so that I don't have to worry about the spaces between = and Name as well as the E in Name and the %>
I tried:
body = %q(
Hello <%= Name %>,
This is a test. hello test
some more stuff here
and here.
<%= Name %>
)
parsed_body = body.gsub(/\A<%= Name %>\Z/, "Some person")
puts parsed_body
When parsed_body is printed out, the string is unchanged. What is wrong with my regex?
In your Regex, you have added the \A and \z anchors. These ensure that your regex only matches, if the string only contains exactly <%= Name %> with nothing before or after.
To match the your pattern anywhere in the string, you can simply remove the anchors:
parsed_body = body.gsub(/<%= Name %>/, "Some person")
Just another option considering what I am assuming you are trying to accomplish
tag_pattern = /(?<open_tag><%=\s*)(?<key>(\w+))(?<close_tag>\s*%>)/
body = <<-B
Hello,
My name is <%= Name %> and I know some things. Just because I am a
<%= Occupation %> doesn't mean I know everything, but I sure can
<%=Duty%> just as well as anyone else.
Also please don't replace <%= This %>
Thank you,
<%= Name %>
B
dict = {"Name" => "engineersmnky", "Occupation" => "Monkey", "Duty" => "drive a train"}
body.gsub(tag_pattern) {|m| dict[$2] || m }
#=> Hello,
# My name is engineersmnky and I know some things. Just because I am a
# Monkey doesn't mean I know everything, but I sure can
# drive a train just as well as anyone else.
# Also please don't replace <%= This %>
#
# Thank you,
# engineersmnky
In this case I used a dictionary of the anticipated portions of the "erb" to be replaced and used the block style of String#gsub to handle the replacements where $2 is the named capture key. When there is not a matching key it just leaves the match untouched e.g. "Also please don't replace <%= This %>"
You could implement this with any pattern you choose but if you are going to use "erb" style lines maybe try leveraging erb other wise the same will work below:
tag_pattern = (?<open_tag>{!!\s*)(?<key>(\w+))(?<close_tag>\s*!\?})
body = <<-B Hello,
My name is {!! Name !?} and I know some things. Just because I am a
{!! Occupation !?} doesn't mean I know everything, but I sure can
{!!Duty !?} just as well as anyone else.
Thank you,
{!! Name !?}
B
As long as you define tag_pattern correctly the replacement is fairly simple. Rubular Example
It looks like you're trying to write your own template parser, which is asking for a lot more trouble that it's worth considering those already exist.
However, this is the basic idea for such a thing:
erb = <<EOT
Owner: <%= name %>
Location: <%= address %>
EOT
FIELD_DATA = {
name: 'Olive Oyl',
address: '5 Sweethaven Village'
}
FIELD_RE = Regexp.union(FIELD_DATA.keys.map(&:to_s)).source # => "name|address"
puts erb.gsub(/<%=\s+(#{FIELD_RE})\s+%>/) { |k|
k # => "<%= name %>", "<%= address %>"
k[/\s+(\S+)\s+/, 1] # => "name", "address"
FIELD_DATA[k[/\s+(\S+)\s+/, 1].to_sym] # => "Olive Oyl", "5 Sweethaven Village"
}
Which, when run, outputs:
Owner: Olive Oyl
Location: 5 Sweethaven Village
This works because gsub can take a regular expression and a block. For every match of the expression it passes in the match to the block, which is then used to return the actual value being substituted in.
If you have a lot of target values, rather than use Regexp.union, instead use the RegexpTrie gem. See "Is there an efficient way to perform hundreds of text substitutions in Ruby?" for more information.
Again, template parsers exist, they've been around a long time, they're very well tested, and they handle edge cases you haven't thought about, so don't write a new partially-implemented one, instead reuse an existing one.

`-%>` tag does not seem to work by default

I have an erb script:
<% foo="second" %>
first <%= foo %> third
When I run this with the erb command, it puts a leading blank line in the output:
% erb junk
first second third
But when I change the closing %> to -%> in the first line, the script fails unless I use erb -T -:
~$ erb junk1
/usr/share/ruby/erb.rb:850:in `eval': junk1:1: syntax error, unexpected ';' (SyntaxError)
_erbout = ''; foo="second" -; _erbout.concat "\n"
^
from /usr/share/ruby/erb.rb:850:in `result'
from /usr/share/ruby/erb.rb:832:in `run'
from /bin/erb:133:in `run'
from /bin/erb:154:in `<main>'
$ erb -T - junk1
first second third
I thought -%> was supposed to be always recognized as a tag to skip the trailing newline. I am testing these templates to use with Puppet, so I assume Puppet will recognize the -%> tag, and this funkiness is just part of the erb command.
In order to enable a trim_mode (-%>), you have to instantiate the ERB object with trim mode parameter, such as:
e = ERB.new(str, nil, '-')
Note that Rails does not use the stdlib's ERB by default - instead, it uses erubis. Documentation on this can feature can be found in Section 6.3 here:
Since 2.6.0, '<%= -%>' remove tail spaces and newline. This is for compatibiliy with ERB when trim mode is '-'. '<%= =%>' also removes tail spaces and newlines, and this is Erubis-original enhancement (cooler than '<%= -%>', isn't it?).
See the ERB documentation for more information. Note also that if you have any training spaces after the -%>, then this can cause the newline to not be trimmed.

How do i ignore line breaks in csv file with ruby but keep a pretty source file?

I have a csv file with about 30 columns that i would like to output, and would like these to appear in my .csv.erb on different lines, for example:
<%= quantity.line_number %>,
<%= quantity.created_at.strftime("%Y-%m-%d %H:%M:%S") %>,
<%= quantity.partner_entity_no %>,
<%= quantity.partner_name %>,
However when I execute this then my .csv file has line breaks after every ',' I would like to 1) keep each column on separate line in source and 2) have non line breaks in the output .csv file. How could I make this happen?
Use the stdlib CSV class to get csv quoting and escaping semantics right. Or more conveniently, use its Array#to_csv helper method.
<% require 'csv' %>
...
<%= [
quantity.line_number,
quantity.created_at.strftime("%Y-%m-%d %H:%M:%S"),
quantity.partner_entity_no,
quantity.partner_name,
].to_csv %>
<%= [quantity.line_number,
quantity.created_at.strftime("%Y-%m-%d %H:%M:%S"),
quantity.partner_entity_no,
quantity.partner_name].join(',') %>

Unwanted whitespace in Erb view

Here's my sinatra code:
get '/' do
foo = 'not bar'
erb :index
end
My layout.erb
<html>
<head></head>
<body>
<%= yield %>
</body>
</html>
My index.erb
<div class="container">
</div>
now the problem is
The extra text (hilighted with yellow) disturbs my design
Any idea why this is happening?
this dosn't happen if I dont use layout and use only index.erb with all html code
[Edit:]
Use of <%= yield -%> throws error (unexpected tUMINUS, expecting kEND ; #_out_buf.concat " "; - yield -; #_out_buf.concat "\n" ) in .... layout.rb
my best guess is the 4 spaces come from the soft tabs in your layout.erb
<body>
____<%= yield %>
</body>
try <body><%= yield%></body>?
I've been using Slim a long while
and
body
= yield
never fails me whitespace
hate ERB
You can set this up with *trim_mode* parameter for ERB
From http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html#method-c-new :
If trim_mode is passed a String containing one or more of the following modifiers, ERB will adjust its code generation as listed:
% enables Ruby code processing for lines beginning with %
<> omit newline for lines starting with <% and ending in %>
> omit newline for lines ending in %>

About using method "print" etc. in ERB for metaprogramming

I am using ERB via console for metaprogramming (for math software). For example, I have file test.erb containing
text line before ruby
<%= 'via <%=' %>
<% print 'print' %>
<% puts 'puts' %>
text line after ruby
When I parse it by $ erb test.erb, I get the following output
printputs
text line before ruby
via <%=
text line after ruby
I am not surprised by it, but wonder if there is a good way to catch output of print method and put it at the place where it is called in the ERB template?
text line before ruby
via <%=
print
puts
text line after ruby
Imagine that I have a complex construction, where I would prefer to print instead of collecting output in a string inside <%= %>.
Update
Just to illustrate the answer of Brian:
text line before ruby
<%= '<%=' %>
% print 'print'
% puts 'puts'
% E = _erbout
% E << '_erbout'+"\n"
text line after ruby
Parsing the file $ erb test.erb:
printputs
text line before ruby
<%=
_erbout
text line after ruby
Not certain if this helps in your particular case, but consider looking at some examples using the _erbout method
text line before ruby
<%= 'via <%=' %>
<% _erbout << 'print' %>
<% _erbout << 'puts' %>
text line after ruby
Hope this gets you somewhere.
As an option, one can redefine Kernel#p method:
file: p_for_erb.rb
module Kernel
alias :p_super :p
def p *args
if args.empty?
##_erbout
elsif args.first.class == Hash
##_erbout = args.first[:init]
else
args.each { |a| ##_erbout << a }
end
end
end
...and then do similar to this:
file: mytest.erb
text before ruby
% require 'p_for_erb'
% p init: _erbout # to initialize class variable ##_erbout
% p "my p output"
Command $ erb mytest.erb produces
text before ruby
my p output

Resources