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
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 need to evaluate an ERB template, and then ensure it's a valid NGINX configuration file, but vanilla ERB doesn't allow the -%> directive. How am I able to add that extension into my rakefile?
I've been able to replicate the problem in irb as so:
~ $ irb
irb(main):001:0> require 'erb'
=> true
irb(main):002:0> var = "yeah"
=> "yeah"
irb(main):003:0> ERB.new(" <% if var == 'yeh' -%>
irb(main):004:1" something
irb(main):005:1" <% else -%>
irb(main):006:1" something else
irb(main):007:1" <% end -%>
irb(main):008:1" ").result binding #"
SyntaxError: (erb):1: syntax error, unexpected ';'
...concat " "; if var == 'yeh' -; _erbout.concat "\nsomething\...
... ^
(erb):3: syntax error, unexpected keyword_else, expecting $end
; else -; _erbout.concat "\nsomething else\n"
^
from /usr/lib/ruby/1.9.1/erb.rb:838:in `eval'
from /usr/lib/ruby/1.9.1/erb.rb:838:in `result'
from (irb):3
from /usr/bin/irb:12:in `<main>'
In order to use the -%> syntax in ERB you need to set the trim mode option to '-'. This is the third option to the constructor, you will need to pass nil as the second (unless you want to change the safe_level from the default):
ERB.new(" <% if var == 'yeh' %>
something
<% else %>
something else
<% end %>
", nil, '-').result binding
Without this option the - is included in the generated Ruby script and gives you the syntax error when you try to run it.
Note that there is another eRuby processor, Erubis which might have slightly different options (it can still use this syntax). This one is used by Rails. Check out the docs for more info.
I am trying to use ERB templating to dynamically create a list of mount points for filesystems, to be monitored for disk usage by Nagios. I am having trouble figuring out the exact syntax for ERB, I have it working in straight Ruby.
Here is what I have tried for ERB
<% #str = `df -h`; #str.scan(/\/[\w\/]+$/){|m| -%><%= -p #m %><% unless m.match(/\/dev|\/proc/)};puts %>
Here is my code, and desired output working in the Ruby CLI:
ruby -e '
str = `df -h`
str.scan(/\/[\w\/]+$/){|m| print "-p #{m} " unless m.match(/\/dev|\/proc/)};puts'
-p /net -p /home -p /Network/Servers <-- Output
First of all, you don't need to run those in the template. You probably have some ruby code lauching the template (like a Rails controller or a Sinatra class). You can put your code there, and store the output to show in the template (example assuming rails).
Second, you don't want to use print or puts (as those would output toward the terminal, not the template), but to store the output in a variable.
The controller:
class MountPointsController < ApplicationController
def index
#output = ""
str = `df -h`
str.scan(/\/[\w\/]+$/){|m| output << "-p #{m} " unless m.match(/\/dev|\/proc/)};output << "\n"
end
end
The template is then as simple as (note the '<%=' that means "output the result in the template):
<%= #output %>
Even if I would recommend against, here is a sample with all the code in the template:
<% #output = "" %>
<% str = `df -h` %>
<% str.scan(/\/[\w\/]+$/){|m| output << "-p #{m} " unless m.match(/\/dev|\/proc/)};output << "\n" %>
<%= #output %>
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)
I need to create 1500+ ruby files from a template for some testing I'm doing with Selenium.
The template looks like this:
class $CLASS_NAME
require "spec"
attr_accessor :title
include Spec::Example::ExampleGroupMethods
include Spec::Matchers
def initialize
#title = "$OLD_URL -> $NEW_URL"
end
def execute(selenium)
selenium.open "$OLD_URL"
sleep 1
puts 'Opening...'
sleep 1
url = selenium.get_location
puts 'Grabbing location...'
sleep 1
puts 'The URL is ' + url
puts 'Doing match...'
sleep 1
/$NEW_URL/.match(url).should_not be nil
puts "\n##### Success! #####\n\r"
end # execute
I have a load of URL's I need to insert - one into each file, replacing '$OLD_URL' and '$NEW_URL'.
Is there anyway to do something like this?
x = 0
while (x < 1500)
{
open template.rb
find all instances of $CLASS_NAME and replace with xxx from classnames.txt
find all instances of $OLD_URL and replace with xxx from listofurls.csv
find all instances of $NEW_URL and replace with xxx from listofurls.csv
save file as ('redirect_' + 'x++')
x++
}
The proper way to do it is using the ERB library.
The code below will generate two files according to predefined template.
require "erb"
File.open("template.erb") do |io|
template = ERB.new io.read
files = {:anecdote => "There are 10 types of people in the world.",
:story => "Once upon a time..."}
files.each do |file, contents|
File.open "#{file}.txt", "w" do |out|
out.puts template.result binding
end
end
end
When template.erb looks like:
Title <%= file %>
<%= "=" * 40 %>
<%= contents %>
<%= "=" * 40 %>
Here is the contents of aneqdote.txt:
Title anecdote
========================================
There are 10 types of people in the world.
========================================
Read the contents of template.rb to a string, then use String#gsub to edit the template inside the loop and save the modified template.