How to pass and render a ruby variable in a markdown file? Gem "redcarpet" - ruby

I'm using the gem "redcarpet". And I have a markdown file. I want to be able to render it with some ruby variables. Something like this:
# my_file.md
###Something
fdafdsfdsfds
---
<% for n in my_numbers do %>
<%= n %>
<% end %>
What's the proper way to do something like this? How can I pass and render a ruby
variable?

You can use the erb library which is included in ruby, but you have to require it:
require 'erb'
require 'redcarpet'
input = File.read "./file.md"
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
output = markdown.render ERB.new(input).result(binding)
File.open("output.html", "w") { |f| f.write output }
You can customize the markdown renderer by referencing the redcarpet readme

Related

How to use ActionView/Erubi outside Rails

I frequently use Sinatra for smallish projects. It's pretty good for what I need but I miss the ability to mark strings as HTML safe, and then ERB knowing when to escape or not escape accordingly.
I'd really like it if I could rip out the patches that Rails makes to Erubi (around here) and then apply those patches to Erubi myself so that tilt can just use the monkey-patched Erubi and everyone lives happily ever after. However, after digging around in the source, it's not clear to me how I could actually accomplish that.
I also tried to find some way to get an interface into ActionView like the render method, but I couldn't even find where that was defined.
How can I use ActionView outside of Rails, ideally by using ActionView's monkey-patches to Erubi, or if that won't work, how else can I use ActionView to go from template string to rendered string outside Rails?
Specifically, I'd like to be able to do the following:
def some_wrapper_func(unescaped_html)
"<div>#{h unescaped_html}</div>".html_safe
end
# test1.erb
hello world <%= "<script>alert('hi');</script>" %> <%= some_wrapper_func("<span>foobar</span>") %>
#=> hello world <script>alert('hi');</script> <div><span>foobar</span></div>
What you need here is ActiveSupport. I'm not sure if it is overkill or not, but you can do this:
#app.rb:
require 'sinatra'
require 'active_support/all'
get '/' do
erb :index
end
And in a view:
#views/index.erb
Hello, world!
<%= "<script>alert('Hello!')</script>".html_safe %>
Mind that requre 'active_support' will load nothing and requre 'active_support' will load all modules. You can specify what modules do need as described
in Active Support Core Extensions.
If the only goal is to enable auto-escaping, there is no need for ActionView at all. It can be done like this (mind the <%== %> tag):
#app.rb
require 'sinatra'
require 'erubis'
set :erb, :escape_html => true
get '/' do
erb :index
end
#View
<%= "<script>alert('Hello, and it will not produce alert!')</script>" %>
<%== "<script>alert('Hello and it will!')</script>" %>
We will try to get ActionView up and running with Sinatra (or any Ruby program):
require 'sinatra'
require 'action_view'
get '/' do
av_render :index
end
def av_render view
paths = ActionView::PathSet.new(["views"])
lookup_context = ActionView::LookupContext.new(paths)
renderer = ActionView::Renderer.new(lookup_context)
view_context = ActionView::Base.new(renderer)
renderer.render(view_context, template: view)
end
And in the view we use html_safe:
<%= "<script>alert('Hello, and it will not produce alert!')</script>" %>
<%= "<script>alert('Hello and it will!')</script>".html_safe %>
Wrapper functions also work with this approach. The only problem here is a custom-render method, but it can be avoided.
If you'd like to avoid ActionView entirely and just use Tilt+Erubi, you can actually create for yourself a SafeString class and have Erubi use it for compilation.
Erubi takes some important options, specifically:
- escape: If this is true, then <%= %> will escape by default, otherwise only <%== %> will escape by default
- bufval: Internally, erubi uses what is basically an accumulator to build up your template. This is the value that it will initialize that accumulator to. It is important that it has a <<(str) method to concat new pieces on, and a to_s method to get the return value out.
- escapefunc: The function that Erubi will use for escaping. It's important to override this, because we'll want to escape anything that isn't a SafeString but let SafeStrings pass through unchanged.
So, first let's define this SafeString class:
# main.rb
require 'tilt'
require 'erubi'
class SafeString
def initialize(str = '')
#str = str
end
def <<(str)
if str.is_a? String
return (#str << str)
elsif str.is_a? SafeString
#str = #str << str
return self
else
throw "Can't concat"
end
end
def to_s
#str
end
def self.escape(val)
if val.is_a? SafeString
return val.to_s
else
return Erubi.h(val.to_s)
end
end
module Helpers
def raw(content)
SafeString.new(content)
end
end
end
Then, we'll need to include the raw helper we defined and to test it on an ERB file:
include SafeString::Helpers
puts Tilt::ErubiTemplate.new("somefile.erb", bufval: 'SafeString.new', escapefunc: 'SafeString.escape', escape: true).render
# somefile.erb
<%= "<script>alert('Hello, and it will not produce alert!')</script>" %>
<%= raw("<script>alert('Hello and it will!')</script>") %>
And this will give us the output we desire!
# stdout
<script>alert('Hello, and it will not produce alert!')</script>
<script>alert('Hello and it will!')</script>
To improve this, instead of this minimal SafeString class, you could use ActiveSupport::SafeBuffer.

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/

Access 'ENV' variable in YAML file

I have a custom yaml file that needs to use an ENV variable.
YAML.load_file('config/databases.yml')
Need to access the PASSWORD variable from the ENV variable like the below from the yaml file
TEST:
PASSWORD: ENV["TEST_DB_PW"]
This is not a RAILS app.
How do I do this? <% ENV["TEST_DB_PW"] %> works on RAILS but does not work if it is a simple ruby script.
require 'yaml'
class Databases
def initialize
if File.exist?('config/databases.yml')
#databases=YAML.load_file('config/databases.yml')
else
# You screwed up...
end
end
end
def print_data
#databases['TEST']['PASSWORD']
end
print_data needs resolving to the ENV parameter referenced in the YAML file.
<% ENV["TEST_DB_PW"] %> works on RAILS but does not work if it is a simple ruby script.
<% ... %> is an ERB tag. In order to use it, you have to parse the file accordingly.
Assuming you have a file config/database.yml:
TEST:
PASSWORD: <%= ENV["TEST_DB_PW"] %>
You can load it via:
require 'yaml'
require 'erb'
ENV["TEST_DB_PW"] = "secret"
YAML.load(ERB.new(File.read('config/database.yml')).result)
#=> {"TEST"=>{"PASSWORD"=>"secret"}}
This works for me and was confirmed by #halfelf
eval(#databases['TEST']['PASSWORD'])
if you want to assign it to a variable then
password = eval("#{#databases['TEST']['PASSWORD']}")

How to extend ERB templating

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

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