Ruby ERB how to create list of mount points - ruby

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

Related

Emulation for ERB extention -%> for the purpose of unittests

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.

Ruby - trying to make hashtags within string into links

I am trying to make the hashtags within a string into links.
e.g. I'd like a string that's currently: "I'm a string which contains a #hashtag" to transform into: "I'm a string which contains #hashtag"
The code that I have at the moment is as follows:
<% #messages.each do |message| %>
<% string = message.content %>
<% hashtaglinks = string.scan(/#(\d*)/).flatten %>
<% hashtaglinks.each do |tag| %>
<li><%= string = string.gsub(/##{tag}\b/, link_to("google", "##{tag}") %><li>
<% end %>
<% end %>
I've been trying (in vain) for several hours to get this to work, reading through many similar stackoverflow threads- but frustration has got the better of me, and as a beginner rubyist, I'd be really appreciate it if someone could please help me out!
The code in my 'server.rb' is as follows:
get '/' do
#messages = Message.all
erb :index
end
post '/messages' do
content = params["content"]
hashtags = params["content"].scan(/#\w+/).flatten.map{|hashtag|
Hashtag.first_or_create(:text => hashtag)}
Message.create(:content => content, :hashtags => hashtags)
redirect to('/')
end
get '/hashtags/:text' do
hashtag = Hashtag.first(:text => params[:text])
#messages = hashtag ? hashtag.messages : []
erb :index
end
helpers do
def link_to(url,text=url,opts={})
attributes = ""
opts.each { |key,value| attributes << key.to_s << "=\"" << value << "\" "}
"<a href=\"#{url}\" #{attributes}>#{text}</a>"
end
end
Here is the code to get you started. This should replace (in-place) the hashtags in the string with the links:
<% string.gsub!(/#\w+/) do |tag| %>
<% link_to("##{tag}", url_you_want_to_replace_hashtag_with) %>
<% end %>
You may need to use html_safe on the string to display it afterwards.
The regex doesn't account for more complex cases, like what do you do in case of ##tag0 or #tag1#tag2. Should tag0 and tag2 be considered hashtags? Also, you may want to change \w to something like [a-zA-Z0-9] if you want to limit the tags to alphanumerics and digits only.

Ruby Sinatra: show clickable list of files

i have this simple script to show all files in a folder, it works in the console but gives a different result in Sinatra (with path and extension). Why is this so, and how can i best present these basenames (without path and extension) in a ul list as a link to open this file in the browser using Sinatra ?
The goal is to present a clickable list of pages to open if no filename is given. I allready have the routine to show the files.
console:
require 'find'
def get_files path
dir_array = Array.new
Find.find(path) do |f|
dir_array << f if !File.directory?(f) # add only non-directories
end
return dir_array
end
for filename in get_files 'c:/sinatra_wiki/views'
basename = File.basename(filename, ".*")
puts basename
end
=> index
index2
Sinatra:
require 'find'
def get_files path
dir_array = Array.new
Find.find(path) do |f|
dir_array << f if !File.directory?(f) # add only non-directories
end
return dir_array
end
get '/' do
for filename in get_files 'c:/sinatra_wiki/views'
basename = File.basename(filename, ".*")
puts basename
end
end
=> c:/sinatra_wiki/views/index.htmlc:/sinatra_wiki/views/index2.erb
In your sinatra implementation, the result you see in the browser is not the one from the puts basename statement in the get block. It's the return value of the get_files method. Try adding puts "<p>#{base name}</p>" instead of the puts basename in the get block and see for yourself.
Some changes:
The get_files method: Instead of sending the entire file path, send only the file name
dir_array << File.basename(f, ".*")
Add a view in case you need clarity:
get '/' do
#arr = get_files(the_path)
erb :index
end
elsewhere, in the app/views folder, in an index.erb file:
<h2>Page list</h2>
<ul>
<% #arr.each do |page| %>
<li><%=page> %></li>
<% end %>
</ul>
This is to list out the file names in a similar way to that of the console output.
TL;DR: Put the looping part in the view!

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

How can I create a program to create multiple files from one template with different values inside?

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.

Resources