Rendering HAML partials from within HAML outside of Rails - ruby

I'm using HAML to generate some static html pages for a site, and I was wanting to split out common components into partials that I can include in multiple pages, just like in Rails. However I don't want to use the whole Rails stack to do this as it seems like overkill.
I've looked around on the Internet but haven't found anything, better than just doing something like:
Haml::Engine.new(IO.read("header.haml")).render
Is there a nicer way of including so-called partials from within HAML? An existing filter or command that I'm missing?

It's best to combine haml & sass with a tool for building static websites. Here's some links:
StaticMatic
Serve
Haml Jekyll -- a fork of Jekyll that supports haml.
Middleman
I'm using jekyll for my blog, but if you're not building a blog it's probably not appropriate for your needs.

Darn, you're right – there isn't a built-in way. I've used helpers with the haml command line, but always ones whose output was already HTML formatted.
My best suggestion is to write a partial() method and require it. It looks like you have already started down this path. I would suggest anyone writing such a function consider keeping the original binding around in some way. Haml::Helpers#capture_hame looks to be the easiest way to make this happen.
If execution speed is an issue, it might also be a good idea to cache some of the parsed template in the same way that Merb does it.
If someone does get some code working, please put it up on GitHub and make a comment here.

I finally found what I was looking for, so I thought I'd share my find with you. you can simply use the same syntax you use for haml in the first place - http://www.semicomplete.com/blog/geekery/partials-in-haml-in-sinatra.html
/views/file.haml
%h3 Title
%div= haml :content, :layout => false
/views/content.haml
%p your content here

All of the solutions seemed bulky for my purposes, though I'm trying to do basically the same thing. Here is a ruby script I wrote that does precious little - evaluates Haml with the option to stick in = partial "test.haml" anywhere you like. It does a trivial amount of logic to try and find a partial file.
require 'haml'
def find filename
return filename if File.exists? filename
path = File.dirname ARGV[0]
filename = path+"/"+filename
return filename if File.exists? filename
throw "Could not find file."
end
def partial filename
source = File.read(find(filename))
engine = Haml::Engine.new(source)
engine.render(binding)
end
puts partial ARGV[0]
you execute it like so : ruby hamlize.rb input.haml > output.html

I had the same problem. I needed to generate some html snippets to optimize the server response, once this snippets have a lot of calculations(for drawing graphs) and every time a user do a request it was doing all the stuff unnecessarily.
Once i have the views partitioned in several haml partials, i wanted to reuse this to generate the html files.
My first approach was trying with the Haml engine, but once i have partials rendering other partials and some functions of the application helper, it didn't worked.
Finality i found a solution that passed by creating a function in the models that i wanted to create an html file ( to_html ) Here is it:
def to_html
ActionView::Base.send :include, ActionView::Helpers::ApplicationHelper
File.open(File.join(Rails.root, "public", 'test.html'), "w") do |file|
file.print ActionView::Base.new(Rails.configuration.paths["app/views"].first).render(
:partial => 'partial_folder/partial',
:format => :html,
:locals => { :model => self}
)
end
end
This way, i was able to use the already done partials, to print the html files.
This worked for me, maybe it can help you also.

Related

Is it possible to require a Ruby file in an ERB template?

I know that you can embed Ruby code in an ERB template. But I have this massive file that has over 200 lines of code. It wouldn't make sense to place every line into the ERB file as then the page would be too big.
I think a better solution would be to require a Ruby file in ERB. Is this possible? If so, how do I do it?
My code itself has a lot of methods defined and I'm not sure they can be added to a view file anyways.
The program is a game that will be played on the home page.

Multiple Converters/Generators in Jekyll?

I would like to write a Jekyll plugin that makes all posts available in PDF format by utilizing Kramdown's LaTeX export capabilities. For each post in Markdown format, I'd like to end up with the normal .html post along with a .tex file containing the LaTeX markup and finally a .pdf.
Following the documentation for creating plugins, I see two ways of approaching the problem, either with a Converter or with a Generator.
Converter plugins seem to run after the built-in Converters, so the .markdown files have all been converted to .html by the time they reach the Converter.
When I try to implement a Generator, I am able to use fileutils to write a file successfully, but by the end of Jekyll's cycle, that file has been removed. It seems there's a StaticFile class which you can use to register new output files with Jekyll, but I cannot find any real guidance on how to use it.
If you take a look at the ThumbGenerator class in this: https://github.com/matthewowen/jekyll-slideshow/blob/master/_plugins/jekyll_slideshow.rb you'll seen a similar example. This particular plugin makes thumbnail sized versions of all images in the site. Hopefully it gives a useful guide to how you can interact with Jekyll's StaticFile class (though I'm not a Ruby pro, so forgive any poor style).
Unfortunately, there isn't really documentation for this - I gleaned it from reading through the source.
I wrote this a few months ago and don't particularly remember the details (which is why I gave an example rather than a workthrough), but if this doesn't get you on the right track let me know and I'll try to help.
I try to do the same but with direct html->pdf conversion.
It did not work inside a gitlab-ci pipeline at this time, nonetheless it work on my workstation (see here) with a third possibility : a hook !
(here with pdfkit)
require 'pdfkit'
module Jekyll
Jekyll::Hooks.register :site, :post_write do |post|
post.posts.docs.each do |post|
filename = post.site.dest + post.id + ".pdf"
dirname = File.dirname(filename)
Dir.mkdir(dirname) unless File.exists?(dirname)
kit = PDFKit.new(post.content, :page_size => 'Letter')
kit.stylesheets << './css/bootstrap.min.css'
kit.to_file(filename)
end
end
end

Using haml and erb

Can haml be use as a complete replacement for erb and vice versa or are there particular cases where one should be use?
Like for example: is better do X with haml and is better to do Y with erb.
I'm trying to get as quickly as possible to my web app and don't really want to learn both right now if it can be avoided.
I've been using HAML almost exclusively for years and on many projects. I can't remember having to convert any HAML file to ERB.
But I can think of some cases where ERB may be easier:
When you share the templates with people who only know HTML.
When you write content, unless you use markdown or something.
When you import existing HTML (samples, legacy, etc.). To convert them I use html2haml directly in my terminal.
When you need full control on the white spaces in the output HTML. It's rarely needed, but the HAML syntax to handle that is not great.
When you have many ERB files to convert to HAML. Some of them cannot be parsed correctly by html2haml --erb.
And obviously when you don't generate HTML. For example I use ERB to generate text emails, and in Rails generators.
Petty sure HAML can also be used for everything. I'd recommend using ERB to get you started though. It's a lot simpler - everything is HTML until you use a <% %> or <%= %>.
No doubt someone will disagree with me.

How to specify format when calling haml templates in Sinatra

In Sinatra, the following code
haml :index
Will render the file index.html.haml or index.haml
How can I specify file format? I been reading Sinatra README and trying different combinations but I can't see how to do it.
I need to be able to specify a haml template by giving its format too so I can do something like index.js.haml.
Found this while answering another question. Sinatra-Respond_to. May be this is what you're looking for.
As #Kashyap points out
haml :'index.js'
That would do the trick.

Using gzip compression in Sinatra with Ruby

Note: I had another similar question about how to GZIP data using Ruby's zlib which technically was answered and I didn't feel I could start evolving the question since it had been answered so although this question is related it is not the same...
The following code (I believe) is GZIP'ing a static CSS file and storing the results in the result variable. But what do I do with this in the sense: how can I send this data back to the browser so it is recognised as being GZIP'ed rather than the original file size (e.g. when checking my YSlow score I want to see it correctly marking me for making sure I GZIP static resources).
z = Zlib::Deflate.new(6, 31)
z.deflate(File.read('public/Assets/Styles/build.css'))
z.flush
#result = z.finish # could also of done: result = z.deflate(file, Zlib::FINISH)
z.close
...one thing to note is that in my previous question the respondent clarified that Zlib::Deflate.deflate will not produce gzip-encoded data. It will only produce zlib-encoded data and so I would need to use Zlib::Deflate.new with the windowBits argument equal to 31 to start a gzip stream.
But when I run this code I don't actually know what to do with the result variable and its content. There is no information on the internet (that I can find) about how to send GZIP encoded static resources (like JavaScript, CSS, HTML etc) to the browser, this making the page load quicker. It seems every Ruby article I read is based on someone using Ruby on Rails!!?
Any help really appreciated.
After zipping the file you would simply return the result and ensure to set the header Content-Encoding: gzip for the response. Google has a nice, little introduction to gzip compression and what you have to watch out for. Here is what you could do in Sinatra:
get '/whatever' do
headers['Content-Encoding'] = 'gzip'
StringIO.new.tap do |io|
gz = Zlib::GzipWriter.new(io)
begin
gz.write(File.read('public/Assets/Styles/build.css'))
ensure
gz.close
end
end.string
end
One final word of caution, though. You should probably choose this approach only for content that you created on the fly or if you just want to use gzip compression in a few places.
If, however, your goal is to serve most or even all of your static resources with gzip compression enabled, then it will be a much better solution to rely on what is already supported by your web server instead of polluting your code with this detail. There's a good chance that you can enable gzip compression with some configuration settings. Here's an example of how it is done for nginx.
Another alternative would be to use the Rack::Deflater middleware.
Just to highlight 'Rack::Deflater' way as an 'answer' ->
As mentioned in the comment above, just put the compression in config.ru
use Rack::Deflater
thats pretty much it!
We can see that users are going to compress web related data like css files. I want to recommend using brotli. It was heavily optimized for such purpose. Any modern web browser today supports it.
You can use ruby-brs bindings for ruby.
gem install ruby-brs
require "brs"
require "sinatra"
get "/" do
headers["Content-Encoding"] = "br"
BRS::String.compress File.read("sample.css")
end
You can use streaming interface instead, it is similar to Zlib interface.
require "brs"
require "sinatra"
get "/" do
headers["Content-Encoding"] = "br"
StringIO.new.tap do |io|
writer = BRS::Stream::Writer.new io
begin
writer.write File.read("sample.css")
ensure
writer.close
end
end
.string
end
You can also use nonblock methods, please read more information about ruby-brs.

Resources