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
Related
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.
The document going in has a structure like this:
<span class="footnote">Hello there, link</span>
The XPath search is:
#doc = set_nokogiri(html)
footnotes = #doc.xpath(".//span[#class = 'footnote']")
footnotes.each_with_index do |footnote, index|
puts footnote
end
The above footnote becomes:
<span>Hello there, link</span>
I assume my XPath is wrong but I'm having a hard time figuring out why.
I had the wrong tag in the output and should have been more careful. The point being that the <a> tag is getting stripped but its contents are still included.
I also added the set_nokogiri line in case that's relevant.
I can't duplicate the problem:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<span class="footnote">Hello there, link</span>
EOT
footnotes = doc.xpath(".//span[#class = 'footnote']")
footnotes.to_xml # => "<span class=\"footnote\">Hello there, link</span>"
footnotes.each do |f|
puts f
end
# >> <span class="footnote">Hello there, link</span>
An additional problem is that the <a> tag has an invalid href URL.
link
should be:
link
I'd like to use full html syntax with Slim. I don't want the cryptography they offer. But I think it's impossible. Here's my html code and Slim throws an error.
The target:
I want not to output an additional class of div element if some condition is met:
<div class="foo bar"></div> # <-- standard
<div class="foo"></div> # <-- no "bar" class if some condition is met
And here is my Slim code:
<body> # <-- 11th line
- (1..5).each do |i| # <-- The dash means a line of Ruby code...
<div class="foo # <-- ...after it an indentation of lines follows
- if(i != 2) # <-- if "i" is not 2
= bar # <-- output "bar" as additional class for the div
= " data-co="#{i}"> # <-- indentation back, I want an output of the rest
</div>
</body> # <-- 17th line
</html> # <-- 19th line, the last element
Logically everything is all right. All indentations and = and - are obeyed. But I get error:
!! Unexpected error while processing request: tmpl.slim:16: syntax error, unexpected keyword_end, expecting ')
'
; end; _buf << ("</div>");
^
tmpl.slim:17: syntax error, unexpected keyword_end, expecting ')'
; end; _buf << ("</body>"\
^
tmpl.slim:22: syntax error, unexpected keyword_end, expecting ')'
end;end;end;end
I have two questions:
1) Is it possible to fully use html syntax in Slim?
2) How may I solve my issue?
I think you are thinking this the wrong way. If your end goal is to produce two types of opening tags based on one condition, then a simple if else statement will work, which is sort-of what you did. But, because you were writing in multiple lines in an HTML opening tag, SLIM freaked out. Try this out and let me know what happens.
<body>
- (1..5).each do |i|
- if i.eql? 2
<div class="foo">
- else
<div class="foo bar" data-co="#{i}">
</div>
</body>
Is there any clean way to get the contents of text nodes with Nokogiri? Right now I'm using
some_node.at_xpath( "//whatever" ).first.content
which seems really verbose for just getting text.
You want only the text?
doc.search('//text()').map(&:text)
Maybe you don't want all the whitespace and noise. If you want only the text nodes containing a word character,
doc.search('//text()').map(&:text).delete_if{|x| x !~ /\w/}
Edit: It appears you only wanted the text content of a single node:
some_node.at_xpath( "//whatever" ).text
Just look for text nodes:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<p>This is a text node </p>
<p> This is another text node</p>
</body>
</html>
EOT
doc.search('//text()').each do |t|
t.replace(t.content.strip)
end
puts doc.to_html
Which outputs:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
<p>This is a text node</p>
<p>This is another text node</p>
</body></html>
BTW, your code example doesn't work. at_xpath( "//whatever" ).first is redundant and will fail. at_xpath will find only the first occurrence, returning a Node. first is superfluous at that point, if it would work, but it won't because Node doesn't have a first method.
I have <data><foo>bar</foo></bar>, how I get at the "bar" text without doing doc.xpath_at( "//data/foo" ).children.first.content?
Assuming doc contains the parsed DOM:
doc.to_xml # => "<?xml version=\"1.0\"?>\n<data>\n <foo>bar</foo>\n</data>\n"
Get the first occurrence:
doc.at('foo').text # => "bar"
doc.at('//foo').text # => "bar"
doc.at('/data/foo').text # => "bar"
Get all occurrences and take the first one:
doc.search('foo').first.text # => "bar"
doc.search('//foo').first.text # => "bar"
doc.search('data foo').first.text # => "bar"
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 %>