How to extend ERB templating - ruby

I would like to extend ERB so every output tag - <%= %> - content is pre-processed before the result is rendered.
For example,
<%= 'test' %>
should now render
!test!
instead of
test
How can I do this ?

Something like this? (untested)
require 'erb'
template = File.read(template_file)
template.gsub!(/<%=(.*?)%>/, '!\1!')
erb = ERB.new(template)
result = erb.result

There is no straightforward way to do that. Perhaps you can define:
class String; def bang; "!#{self}!" end end
and do
<%= "test".bang %>

Related

How to render a value from an .rb file into an .erb file

I don't have much experience with Ruby all I wan't to do is render a value that I declare in an .rb file in an .erb file.
In my .rb file I have this:
def abc()
begin
"aaaaa"
end
end
In my .erb file I have this:
Hello <% abc %>
When I run the app I only see:
Hello
But I expect to see:
Hello aaaa
Anybody can give me a hand, I don't really know ruby at all. Also I have no idea if this is ruby or ruby on rails so sorry if the tag below is wrong.
In Sinatra, register your method as a helper in .rb file:
helpers do
def abc
"aaaaa"
end
end
Omit parentheses if your methods don't need arguments. Also, begin/end block isn't necessary here.
You can call your helper in .erb template:
<%= abc %>
Don't forget = in the opening tag.
http://sinatrarb.com/intro.html section 'Helpers'.
It's unclear what you want to achieve. But If you just want some text in your erb you can do something like this:
erb :myerb, locals: {text: "aaaaa", saved: false}
myerb.erb
<% if saved %>
Hello <%= text %>
<% endif %>
This would also work for functions.
First of all, you need to be aware that a defined method inherently includes the functionality of a begin/end block so you don´t need to put them again. Assuming you are using sinatra, here is what I think you need:
my.rb
require 'sinatra'
def abc
"aaaa"
end
get '/' do
erb :my, locals: {variable: abc}
end
my.erb
<html>
<body>
<p>
Hello <%= variable %>
</p>
</body>
</html>
Run ruby my.rb and then open http://localhost:4567/

Only execute code in erb if variable exists?

Ruby newbie here who just started using Ruby with .erb templates and I'm having a problem with the code. I have a hangman game that's passing variables from the .rb file to the .erb file and everything was working fine until I tried to check it on initial load (no variables present) and it threw errors. So I figured I'd use defined? with an if statement to check if the variable exists and then execute the code if it does and ignore if doesn't. It works fine when I use:
<% if defined?bad_guesses %>
<%= bad_guesses %>
<% end %>
But the information I need is an array and when I try to use an .each or .times statement like this:
<% if defined?bad_guesses %>
<% bad_guesses.each do |i| %>
<%= i %>
<% end %>
<% end %>
I get:
NoMethodError at /
undefined method `each' for nil:NilClass
C:/Projects/hangman/views/index.erb in block in singleton class
<% bad_guesses.each do |i| %> hangman.rb in block in
erb :index, :locals => {:game_status => game_status, :bad_guesses => bad_guesses, :good_guesses => good_guesses, :word => word}
Any suggestions appreciated.
Also, is this even the proper way to do this? When you make an .erb template that uses variables passed in from a class in your .rb file, how do you ignore it until it exists to the template?
Passing variables using:
get '/' do
if params['make'] != nil
make = params['make'].to_i
game_status, bad_guesses, good_guesses, word = Hangman.get_word(make)
elsif params['guess'] != nil
guess = params['guess'].to_s
game_status, bad_guesses, good_guesses, word = Hangman.check_guess(guess)
end
erb :index, :locals => {:game_status => game_status, :bad_guesses => bad_guesses, :good_guesses => good_guesses, :word => word}
end
Looking at this:
<% if defined?bad_guesses %>
<% bad_guesses.each do |i| %>
<%= i %>
<% end %>
<% end %>
a few points:
defined?a is bad style; use defined?(bad_guesses) or defined? bad_guesses instead.
defined? checks if it's defined, so if you say foo = nil; defined? foo it will be true.
You could alternatively use this:
defined?(bad_guesses) && bad_guesses
On the other hand, undefined instance variables are nil by default:
# it shows undefined
defined? #non_existing_var
# but you can still check if it's truthy:
puts "found" if #non_existing_var
# it won't print anything
Similar to instance variables in this regard are hashes. The default value of an unknown key is nil.
The problem with instance variables is they are not scoped to the partial. Instead, I recommend sending your local variables as a nested hash:
locals: { data: { foo: "bar" } }
Then you can safely check for values which may not exist:
if data[:foo]
# this runs
elsif data[:non_existent]
# this doesnt run
end
For my purposes, the following syntax worked:
<% if some_var %>
<%= some_var %>
<% end %>
This block is rendered if some_var is not nil.

How to implement form_tag helpers without actionview?

I'm working on a Sinatra app and want to write my own form helpers. In my erb file I want to use the rails 2.3 style syntax and pass a block to a form_helper method:
<% form_helper 'action' do |f| %>
<%= f.label 'name' %>
<%= f.field 'name' %>
<%= f.button 'name' %>
<% end %>
Then in my simplified form helper I can create a FormBuilder class and yield the methods to the erb block like so:
module ViewHelpers
class FormBuilder
def label(name)
name
end
def field(name)
name
end
def button(name)
name
end
end
def form_helper(action)
form = FormBuilder.new
yield(form)
end
end
What I don't understand is how to output the surrounding <form></form> tags. Is there a way to append text on only the first and last <%= f.___ %> tags?
Rails has had to use some tricks in order to get block helpers to work as wanted, and they changed moving from Rails 2 to Rails 3 (see the blogposts Simplifying Rails Block Helpers and Block Helpers in Rails 3 for more info).
The form_for helper in Rails 2.3 works by directly writing to the output buffer from the method, using the Rails concat method. In order to do something similar in Sinatra, you’ll need to find a way of writing to the output from your helper in the same way.
Erb works by creating Ruby code that builds up the output in a variable. It also allows you to set the name of this variable, by default it is _erbout (or _buf in Erubis). If you change this to be an instance variable rather than a local variable (i.e. provide a variable name that starts with #) you can access it from helpers. (Rails uses the name #output_buffer).
Sinatra uses Tilt for rendering templates, and Tilt provides an :outvar option for setting the variable name in Erb or Erubis templates.
Here’s an example of how this would work:
# set the name of the output variable
set :erb, :outvar => '#output_buffer'
helpers do
def form_helper
# use the new name to write directly to the output buffer
#output_buffer << "<form>\n"
# yield to the block (this is a simplified example, you'll want
# to yield your FormBuilder object here)
yield
# after the block has returned, write any closing text
#output_buffer << "</form>\n"
end
end
With this (fairly simple) example, an Erb template like this:
<% form_helper do %>
... call other methods here
<% end %>
results in the generated HTML:
<form>
... call other methods here
</form>

What would the erb template look like for a ruby enumerator?

What would the erb template look like for a ruby enumerator? The answer will be a erb template.
require "erb"
# build data class
class Foo < Array
def build
b = binding
# create and run templates, filling member data variables
ERB.new(File.read('test2.erb')).result b
end
end
# setup template data
bar = Foo.new([1,2,3])
puts bar.build
I would like some way of accessing the 1,2,3 items in the erb template.
Focus on Ruby 1.9.3 compatibility.
Note: the Class is an extension of Array, and I want to access the elements of this array in its erb template.
Ok, it was as simple as reaching into the self reference.
<% self.each{|element| %> <%= element %> <% } %>

How do I html_escape text data in a sinatra app?

I have a small Sinatra app which generates html fragments for me from an ERB template.
How do I html_escape the output?
The <%=h somestring %> helper does not exist in Sinatra.
Rack::Utils includes a HTML escape method. http://www.sinatrarb.com/faq.html#escape_html
require 'CGI'
get '/html' do
erb :view
end
def h(html)
CGI.escapeHTML html
end
__END__
##view
<% File.open('my.html') do |f| %>
<%=h f.read() %>
<% end %>

Resources