Unwanted whitespace in Erb view - ruby

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 %>

Related

How to use multiline-string here-doc with interpolation using enumerable or loop blocks

I want to simulate the usage of ERB templates using blocks into multiline-heredoc in Ruby:
Example:
From:
<html>
<body>
<ul>
<% #greetings.each do |greeting| %>
<li><%= greeting %></li>
<% end %>
</ul>
</body>
</html>
Into:
greetings = ['Hello World', 'Hello Earth', 'Hello Mars']
body = (
<<-eos
<html>
<body>
<ul>
#{
greetings.map do |greeting|
<<-eos2
<li>#{greeting}</li>
eos2
end.join
}
</ul>
</body>
</html>
eos
)
^ The above seems to work, but it breaks the syntax highlighting in Atom, and looks very messy to me. Perhaps there's an easier way I hope?
puts body
# <html>
# <body>
# <ul>
# <li>Hello World</li>
#<li>Hello Earth</li>
#<li>Hello Mars</li>
#
# </ul>
# </body>
# </html>
Background:
I am writing inline into the .rb file multiline-string of "example" html values using factory_bot
Other Attempt:
Tried below, but I'm getting syntax errors:
greetings = ['Hello World', 'Hello Earth', 'Hello Mars']
body = (
<<-eos
<html>
<body>
<ul>
#{greetings.each do |greeting|}
<li>#{greeting}</li>
#{end}
</ul>
</body>
</html>
eos
)
P.S. I am aware that I can move the whole thing into an .erb file, but I am more curious to know if there's a way to do it inline, i.e. (for very short strings that need not be moved into a separate .erb
Update:
Thanks to #AlekseiMatiushkin, I resolved the syntax highlighting, I'll still open this question up, just in case anyone finds a simpler way, to do the looping:
Before:
After:
^ also, I thought that I had to use <<-html2 inside the <<-html block, because I thought it would break it, but seems like nested <<-html still worked, so, good! :)
Update:
Unfortunately, reopening the file caused the syntax highlighting to break again. But, I guess, this should be fine for now :)
Won't mark this solved as this isn't a direct answer to my question, but is a direct solution to my problem, as I still wasn't able to solve this in pure here-doc, but that I was able to solve my problem upon a realisation that I can also use ERB inline with here-doc string. But, if it helps anyone, here:
require 'erb'
greetings = ['Hello World', 'Hello Earth', 'Hello Mars']
body = ERB.new(
<<-html
<html>
<body>
<ul>
<% greetings.each do |greeting| %>
<li><%= greeting %></li>
<% end %>
</ul>
</body>
</html>
html
).result(binding)
puts body
# <html>
# <body>
# <ul>
#
# <li>Hello World</li>
#
# <li>Hello Earth</li>
#
# <li>Hello Mars</li>
#
# </ul>
# </body>
# </html>
P.S. To be able to indent code without affecting the here-doc string, and if you are using Ruby >= 2.3, it's better to use the squiggly-heredoc literal: <<~. However, if you're using Ruby < 2.3 but are using Rails, you can use the .strip_heredoc instead.

Removing "\n" from string

When I save the output of a bash command (executed in backticks) to an instance variable, the browser, or more specifically, the variable, removes the "\n" characters. I checked the source code of the page, and it displays like this:
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
line 9
line 10
But the browser displays it like this:
line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9 line 10
I put this on a method that displays the output:
#variable.each_line do |line|
if line !~ /word1| word2/
line.sub("Word_I_don't_want", '')
end
end
But the variable won't be compared to the regular expression, and is printed as a whole. The browser displays a string without <br> as a single line, but the source code shows that new lines are being identified, but not processed. I tried
line.sub("\n", "<br>")
but it didn't work either. Hope someone has some tips for me.
SOLVED:
Thanks to ilan berci I could print the desired values, although the Tin Man pointed out that text should be processed on the controller. So I modified my method:
tempString = String.new
#redes.each_line do |line|
if line !~ /word1|word2/
tempString = tempString + line.sub("word_I_don't_want", "").sub("\n", "<br>")
end
end
#redes = tempString
Because processing the text in the .erb was filling the page code with <br> for every unwanted line (the <br> was casted in every .each_line iteration).
Thanks for the help!
<% #variable.each_line do |line| %>
<% line = if line !~ /word1| word2/ %>
<%line.sub("Word_I_don't_want", '') %>
<% end %>
<%= line %>
<br/>
<% end %>
The problem is how browsers display line-ends and white-space. They "gobble" spaces, tabs, vertical-tabs and line-endings, squeezing them into a single space when displayed.
For instance:
<html>
<body>
foo
bar
</body>
</html>
Will display as foo bar in a browser, even though there is line-end ("\n") between foo and bar.
You can fix that a couple ways:
<html>
<body>
foo<br>
bar<br>
</body>
</html>
Or:
<html>
<body>
<pre>
foo
bar
</pre>
</body>
</html>
would display as:
foo
bar
Whereas:
<html>
<body>
<p>foo</p>
<p>bar</p>
</body>
</html>
would display as:
foo
bar
Browser barely honor whitespace. Words with multiple spaces and line-ends will display as if they only have a single space. If I had a string of characters:
foo\t \n bar
in a page, they would display as:
foo bar
because the browser is trying to be helpful.
How do you "fix" your code? You either wrap your text in a <pre> block, append <br> to the lines where you want line-breaks, or do something fun with CSS to adjust the defaults of <p> or <div> tags. There are lots of ways to get there, you just need to know what you're working with and pick a path.
I've used this in my applications:
def replace_newlines_with_br_tags(text)
h(text).gsub(/\r\n/, '<br />').gsub(/\r/, '<br />').gsub(/\n/, '<br />')
end
You can add this to your application helper and use it in your views, etc.
#variable.gsub(/(?:\n\r?|\r\n?)/, '<br>')
Credits here

in sinatra using erubis, default setting escape_html is true. sometimes hava to unescape

In Sinatra, using erubis, the default setting for escape_html is true.
But sometimes I want to to unescape, because, I do not want to add too much escape_html. Don't repeat yourself. :)
helpers:
def raw(string)
CGI::unescape_html(string)
end
views:
<div class="body">
<%= raw "<h1>Thanks for help...</h1>" %>
</div>
does not work.
Just to add some tips. Erubis has ability to escape (sanitize) expression. Erubis::Eruby class act as the following:
<%= expr %> - not escaped.
<%== expr %> - escaped.
<%=== expr %> - out to $stderr.
<%==== expr %> - ignored.
Source
Not sure about which version of Erubis you use, but it seems like it has a special kind of tag for that particular case: with two equals signs. So the line from your example might look like:
<%== "<h1>Thanks for help...</h1>" %>
Calling to CGI::unescape should not be necessary, because the string is initially not escaped. All you need is to prevent escaping, not undo it.
But if your Erubis don't understand <%==, or if you use ERB, not Erubis, then sorry, I don't know any other solution except of what you said: disable html escape for entire file and use h everywhere you do need escaping.
FYI, in Rails for this also there are special helpers raw and String#html_safe, but as I can see they are part of ActiveSupport and not available in Sinatra.
You can accomplish what you want this way:
Web.rb:
require 'sinatra'
require 'erubis'
set :erb, :escape_html => true
get '/hi' do
#model = Hash.new()
#model[:person] = "<b>World</b>"
erb :hello
end
Layout.erb:
<!DOCTYPE html>
<html>
<head>
<title><%= #title %></title>
</head>
<body>
<%== yield %>
</body>
</html>
Hello.erb:
<div>
<p>Hello, <%= #model[:person] %>!</p>
<p>Hello, <%== #model[:person] %>!</p>
</div>

Rails 3 refactoring issue

The following view code generates a series of links with totals (as expected):
<% #jobs.group_by(&:employer_name).sort.each do |employer, jobs| %>
<%= link_to employer, jobs_path() %> <%= "(#{jobs.length})" %>
<% end %>
However, when I refactor the view's code and move the logic to a helper, the code doesn't work as expect.
view:
<%= employer_filter(#jobs_clone) %>
helper:
def employer_filter(jobs)
jobs.group_by(&:employer_name).sort.each do |employer,jobs|
link_to employer, jobs_path()
end
end
The following output is generated:
<Job:0x10342e628>#<Job:0x10342e588>#<Job:0x10342e2e0>Employer A#<Job:0x10342e1c8>Employer B#<Job:0x10342e0d8>Employer C#<Job:0x10342ded0>Employer D#
What am I not understanding? At first blush, the code seems to be equivalent.
In the first example, it is directly outputting to erb, in the second example it is returning the result of that method.
Try this:
def employer_filter(jobs)
employer_filter = ""
jobs.group_by(&:employer_name).sort.each do |employer,jobs|
employer_filter += link_to(employer, jobs_path())
end
employer_filter
end
Then call it like this in the view:
raw(employer_filter(jobs))
Also note the use of "raw". Once you move generation of a string out of the template you need to tell rails that you don't want it html escaped.
For extra credit, you could use the "inject" command instead of explicitly building the string, but I am lazy and wanted to give you what I know would work w/o testing.
This syntax worked as I hoped it would:
def employer_filter(jobs_clone)
jobs_clone.group_by(&:employer_name).sort.collect { |group,items|
link_to( group, jobs_path() ) + " (#{items.length})"
}.join(' | ').html_safe
end

Word Count with Ruby

I am trying to figure out a way to count a words in a particular string that contains html.
Example String:
<p>Hello World</p>
Is there a way in Ruby to count the words in between the p tags? Or any tag for that matter?
Examples:
<p>Hello World</p>
<h2>Hello World</h2>
<li>Hello World</li>
Thanks in advance!
Edit (here is my working code)
Controller:
class DashboardController < ApplicationController
def index
#pages = Page.find(:all)
#word_count = []
end
end
View:
<% #pages.each do |page| %>
<% page.current_state.elements.each do |el| %>
<% #count = Hpricot(el.description).inner_text.split.uniq.size %>
<% #word_count << #count %>
<% end %>
<li><strong>Page Name: <%= page.slug %> (Word Count: <%= #word_count.inject(0){|sum,n| sum+n } %>)</strong></li>
<% end %>
Here's how you can do it:
require 'hpricot'
content = "<p>Hello World...."
doc = Hpricot(content)
doc.inner_text.split.uniq
Will give you:
[
[0] "Hello",
[1] "World"
]
(sidenote: the output is formatted with awesome_print that I warmly recommend)
Sure
Use Nokogiri to parse the HTML/XML and XPath to find the element and its text value.
Split on whitespace to count the words
You'll want to use something like Hpricot to remove the HTML, then it's just a case of counting words in plain text.
Here is an example of stripping the HTML: http://underpantsgnome.com/2007/01/20/hpricot-scrub/
First start with something able to parse HTML like Hpricot, then use simple regular expression to do what you want (you can merely split over spaces and then count for example)

Resources