I have an array #cities = ["Vienna", "Barcelona", "Paris"];
and I am trying to display the individual items with a spacer in between. However it is possible that there is only 1 element in the array, in which case I do not want to display the spacer. And also the array could be empty, in which case I want to display nothing.
For the above array I want the following output:
Vienna
-----
Barcelona
-----
Paris
I use an erb template cityview to apply formatting, css, etc before actually printing the city names. Simplified, it looks like this:
<p><%= #cities[#city_id] %></p>
I have implemented it as follows...
unless #array.empty?
#city_id = 0;
erb :cityview
end
unless #array[1..-1].nil?
#array[1..-1].each_index do |i|
#city_id = i+1;
puts "<p>-------</p>";
erb :cityview
end
end
Is there a better way?
#cities.join("<p>--------</p>")
Edit to address the template
Here I'm assuming that there's an erbs method that returns the rendered template without doing a puts. Returning the string allows easier manipulation and reuse.
#cities.map { |c| #city = c; erb :cityview }.join("<p>--------</p>")
I'd prefer:
erb:
<p><%= #city %></p>
and loop
#array.each_with_index do |e, i|
#city = e
erb :cityview
puts "<p>-------</p>" if i < #array.length - 1
end
I assume you have split the erb, bit because you want to customize it.
If you want to mix HTML with your city names then you'll need to worry about HTML encoding things before you mix in your HTML. Using just the standard library:
require 'cgi'
html = #cities.map { |c| CGI.escapeHTML(c) }.join('<p>-----</p>')
If you're in Rails, then you can use html_escape from ERB::Util and mark the result as safe-for-HTML with html_safe to avoid having to worry about the encoding in your view:
include ERB::Util
html = #cities.map { |c| html_escape(c) }.join('<p>-----</p>').html_safe
The simpler solution would be to use a spacer template.
http://guides.rubyonrails.org/layouts_and_rendering.html#spacer-templates
Related
I just want to make a simple each loop in my Middleman helper, datas are stored in my page'Frontmatter like this :
dir:
- test
- test2
So in my helper, I try to write my loop :
def translate_directory
current_page.data.dir.each do |dir|
dir
end
end
call my method in my page
<%= translate_directory %>
and this is what's display :
["test", "test2"]
But now, if I make the same loop in my page, write with ERB syntax :
<% current_page.data.dir.each do |x| %>
<%= x %>
<% end %>
the exit is the following
test test2
separated in two strings, so exactly what I want.
EDIT : when I puts the helper'method, it display the two strings in two lines, so in two separated strings. Don't understand why it appear as an array on my browser.
EDIT 2 : a little thing I forgot, I want to translate each word with I18n.translate, like this :
def path_translate
current_page.data.dir.each { |dir| t("paths.#{dir}", locale: lang) }
end
but i can't because the each method doesn't work so I18n can't translate each word.
Because your helper is returning an array not a interpolated string like the ERB template is doing. Try the following for your helper:
def translate_directory
current_page.data.dir.join(' ')
end
My bad. Using .map instead of .each fix the problem, then use .join makes the array a big string.
I'm writing a helper for a small Sinatra app that prints some gaming cards stored as hash in an array.
Every card has this structure:
{ card: 'Ace', suit: :spades, value: 11 }
and the filename of the card image is "spades_11.jpg".
I'm writing a helper to display the cards in my view:
def view(hand)
hand.each do |card|
#print the card
end
end
I need an output like this:
.span2
%img(src="/images/#{card[:suite]}_#{card[:value]}")
How can I insert my Haml code inside the helper block keeping the indentation?
The simplest solution would be to just return the HTML directly from your helper as a string:
def view(hand)
hand.map do |card|
"<div class='span2'><img src='/images/#{card[:suite]}_#{card[:value]}'></div>"
end.join
end
The call it from your Haml with something like:
= view(#the_hand)
You could make use of the haml_tag helper which would let you write something like:
def view(hand)
hand.each do |card|
haml_tag '.span2' do
haml_tag :img, 'src' => "/images/#{card[:suite]}_#{card[:value]}"
end
end
end
Note that haml_tag writes directly to the output rather than returning a string, so you would have to use it with - rather than =:
- view(#the_hand)
or use capture_haml.
This method means your helper depends on Haml. The first method would be usable whatever template language you used, but wouldn’t respect settings like format for whether to end the img tag with />.
If you want to use pure Haml for the markup for each card (this example is simple enough to get away with helpers, but you would certainly want to do this for more complex sections) you could use a partial. Add you Haml code to a file named e.g. view.haml, then you can render it from the containing template, passing in the hand as a local variable:
view.haml:
- hand.each do |card|
.span2
%img(src="/images/#{card[:suite]}_#{card[:value]}")
Parent template:
= haml :view, :locals => {:hand => #the_hand}
You should be able to use a here doc
def view(hand)
hand.each do |card|
<<-HAML
.span2
%img(src="/images/#{card[:suite]}_#{card[:value]}")
HAML
end
end
but note that here docs take the whitespace from the start of the line the are on, so unfortunately this will make your indentation somewhat ugly.
For anything more complicated it probably makes sense to write your haml in a separate .haml file.
Is it possible to convert HTML with Nokogiri to plain text? I also want to include <br /> tag.
For example, given this HTML:
<p>ala ma kota</p> <br /> <span>i kot to idiota </span>
I want this output:
ala ma kota
i kot to idiota
When I just call Nokogiri::HTML(my_html).text it excludes <br /> tag:
ala ma kota i kot to idiota
Instead of writing complex regexp I used Nokogiri.
Working solution (K.I.S.S!):
def strip_html(str)
document = Nokogiri::HTML.parse(str)
document.css("br").each { |node| node.replace("\n") }
document.text
end
Nothing like this exists by default, but you can easily hack something together that comes close to the desired output:
require 'nokogiri'
def render_to_ascii(node)
blocks = %w[p div address] # els to put newlines after
swaps = { "br"=>"\n", "hr"=>"\n#{'-'*70}\n" } # content to swap out
dup = node.dup # don't munge the original
# Get rid of superfluous whitespace in the source
dup.xpath('.//text()').each{ |t| t.content=t.text.gsub(/\s+/,' ') }
# Swap out the swaps
dup.css(swaps.keys.join(',')).each{ |n| n.replace( swaps[n.name] ) }
# Slap a couple newlines after each block level element
dup.css(blocks.join(',')).each{ |n| n.after("\n\n") }
# Return the modified text content
dup.text
end
frag = Nokogiri::HTML.fragment "<p>It is the end of the world
as we
know it<br>and <i>I</i> <strong>feel</strong>
<a href='blah'>fine</a>.</p><div>Capische<hr>Buddy?</div>"
puts render_to_ascii(frag)
#=> It is the end of the world as we know it
#=> and I feel fine.
#=>
#=> Capische
#=> ----------------------------------------------------------------------
#=> Buddy?
Try
Nokogiri::HTML(my_html.gsub('<br />',"\n")).text
Nokogiri will strip out links, so I use this first to preserve links in the text version:
html_version.gsub!(/<a href.*(http:[^"']+).*>(.*)<\/a>/i) { "#{$2}\n#{$1}" }
that will turn this:
link to google
to this:
link to google
http://google.com
If you use HAML you can solve html converting by putting html with 'raw' option, f.e.
= raw #product.short_description
I know we can do things like this:
puts <<START
----Some documents
#{if true
"yesyesyesyesyesyesyesyesyesyes"
else
"nonononononononononononononono"
end}
----Some documents
START
But is it possible to do like this:
puts <<START
----Some documents
#{if true}
yesyesyesyesyesyesyesyesyesyes
#{else}
nonononononononononononononono
#{end}
----Some documents
START
Why I want this is because I hate single/double-quotes in here document, avoiding them will make the document clearer
anyone can help?
thanks!
Maybe you actually want to use ERB if the intention is to perform templating. ERB will support splitting the if/else fine:
require 'erb'
template = ERB.new <<-DOC
----Some documents
<% if true %>
yesyesyesyesyesyesyesyesyesyes
<% else %>
nonononononononononononononono
<% end %>
----Some documents
DOC
string = template.result(binding)
I'll give the alternative I would favour, which is to use heredocs assigned to variables that are then inserted in a master heredoc, as it gets the conditional outside of the heredoc, thus giving the better clarity you're looking for (especially when things start getting more complicated than a contrived example):
cond = if true
<<TRUE
yesyesyesyesyesyesyesyesyesyes
TRUE
else
<<NOTTRUE
nonononononononononononononono
NOTTRUE
end.strip
puts <<START
----Some documents
#{cond}
----Some documents
START
If you're looking for a template then there are plenty out there, and plenty better than ERB in my opinion (start with looking at Haml).
You could consider nested heredocs:
puts <<EOF
---- Some documents
#{if true; <<WHENTRUE
yesyesyes
WHENTRUE
else <<WHENFALSE
nonono
WHENFALSE
end
}---- Some documents
EOF
Note that you need to place the closing } on the beginning of the line or you will have an extra empty line.
Edit: You could avoid that and perhaps get a bit nicer syntax by using a little helper function:
def if_text(condition, whentrue, whenfalse)
(condition ? whentrue : whenfalse).chomp
end
puts <<EOF
---- Some documents
#{if_text(true, <<ELSE, <<ENDIF)
yesyesyes
ELSE
nonono
ENDIF
}
---- Some documents
EOF
You could use ERB if you really wanted something like that:
str = <<-ERB
----Some documents
<% if true %>
yesyesyesyesyesyesyesyesyesyes
<% else %>
nonononononononononononononono
<% end %>
----Some documents
ERB
erb = ERB.new(str, nil, '<>');
puts erb.result(binding)
I have here is a module that replaces the smilies (like ":-)") as icons:
module Smileize
PATH = "/images/smiles"
SMILES = [/\;\-?p/i, /\$\-?\)/, /8\-?\)/, /\>\:\-?\(/, /\:\-?\*/, /\:\-?o/i, /\:\-?c/i, /\;\-?\)/,
/\:\-?s/i, /\:\-?\|/, /\:\-?p/i, /\:\-?D/i, /\:\-?\?/, /\:\-?\(/, /\:\-?\)/]
def to_icon(key)
return "<img class='smiley' src='#{PATH}/smile#{SMILES.index(key) + 1}.png'/>"
end
module_function :to_icon
end
class String
def to_smile
Smileize::SMILES.each do |smile|
if self =~ smile
self.gsub!(smile, Smileize.to_icon(smile))
end
end
self
end
end
So pictures show that I'm using html_safe, like this:
<%= #message.text.to_smile.html_safe %>
But it does not suit me, because but pictures will be displayed and other tags, too.
My question is: how to display only my smile, ignoring the other tags?
I think you'll need to do it like this:
HTML encode the string.
Perform your substitution.
Mark the final result as HTML safe.
Add a helper something like this:
def expand_smilies(s)
s = ERB::Util::html_escape(s)
Smileize::SMILES.each do |smile|
s.gsub!(smile, Smileize.to_icon(smile))
end
s.html_safe
end
And then in your ERB:
<%= expand_smilies some_text %>
ERB uses ERB::Util::html_escape to encode HTML so using it yourself makes sense if you're targeting ERB. Calling html_safe on a string returns you something that ERB will leave alone when it is HTML encoding things.
Note that there is no usable html_safe! on strings and html_safe returns an ActiveSupport::SafeBuffer rather than a String so you'll have to use a helper rather than monkey patching a new method into String. ActiveSupport does patch an html_safe! method into String but all it does is raise an exception saying "don't do that":
def html_safe!
raise "You can't call html_safe! on a String"
end