Using Ruby and Sinatra, Is it possible to use HAML in an "internal" or "inline" manner? - ruby

I've done gem install sinatra and gem install haml
And I have this .rb file
require 'sinatra'
get '/abc2' do
"<b>aaaaaaaaaaaaa</b>"
end
Now say I want that line of HTML but in HAML. and not externally
I know I can do
get '/abc' do
haml :index # /views/index.haml
end
And index.haml could have a line of haml %b aaaaaaa
But is there any way that I can include %b aaaaaaa in my ruby file itself and have it rendered. Without having to refer to a file e.g. without having to refer to /views/index.haml ?
Like CSS lets you have the CSS External, or it lets you have it internal within the html file.. Similarly, Javascript lets you import javascript externally, or it lets you have it internal to the html file.. Well i'm asking about using HAML internally to the .rb file. Is it possible?
I know HAML is intended as a template language for injecting data into.. but it is also a shorthand for writing HTML more concisely.

For small apps you can add the views at the end of your script so there are no external files.
get '/abc' do
haml :hello
end
__END__
## hello
%h1= "Hello there"

You should be able to use Haml::Engine#render to convert the Haml to HTML like so:
get '/abc2' do
Haml::Engine.new(<<-Haml).render(binding)
%b aaaaaa
Haml
end
This uses a heredoc (everything between the <<-Haml line and the closing Haml. binding is a special variable that basically refers to the current scope.

Related

How to stop 'require_relative' requiring itself?

In my Ruby without Rails application, I have a bunch of methods saved in various files, like methods.rb, other_methods.rb etc, that I want to access from my main file, main.rb.
Rather than spell out each 'require_relative' individually, my main.rb file currently reads:
main.rb
Dir["./*.rb"].each {|file| require_relative file }
puts "executing"
The only problem is this outputs:
"executing"
"executing"
My current hacky approach is:
Dir["./*.rb"].each {|file| next if file == "./main.rb"; require file }
Is there a better way?
Should I be wrapping my methods in a Module, or a Mixin instead and then using 'include'?

How can I pass instance variables to a HAML template on the command line?

Background
I'm trying to test the formatting of some HAML templates outside of Rails. The idea is to pass in some instance variables on the command line or via an included Ruby file, rendering the template to standard output. I tried this several different ways without success, as outlined below.
Requiring a Ruby File
For example, given the following two files:
HAML template: "test.haml"
!!!
%h1 Testing HAML CLI
%p= #bar
%p= #baz
Ruby file: "test.rb"
#foo = 'abc'
#bar = '123'
I would expect an invocation like haml -r ./test test.haml to return an interpolated HTML file on standard output, but it doesn't. Instead, I get just the HTML:
<!DOCTYPE html>
<h1>Testing HAML CLI</h1>
<p></p>
<p></p>
Programmatic Attempt
Since this didn't work, I also tried to do this programmatically. For example:
#!/usr/bin/env ruby
require 'haml'
#foo = 'abc'
#bar = '123'
engine = Haml::Engine.new(File.read 'test.haml')
puts engine.render
with exactly the same results, e.g. just the HTML with no variable interpolation.
Restating the Question
Clearly, something else is needed to get HAML to render the template with its associated variables. I would prefer to do this from the command line, either by passing arguments or including a file. How should I be invoking HAML from the command line to make it happen?
If that's not possible for whatever reason, how should I invoke HAML programmatically to perform the interpolation without depending on Rails?
You can supply a scope object and a local variables hash to the render method. In your example case, you would call:
engine = Haml::Engine.new(File.read 'test.haml')
engine.render(Object.new, { :#foo => 'abc', :#bar => '123' })
The reason that both of these examples are not working is that you are attempting to access instance variables from a different class. The simplest solution is to define and use methods instead of attempting to access another classes instance variables as if they were your own.
I.E. in test.rb
def foo
'abc'
end
test.haml
!!!
%h1 Testing HAML CLI
%p= foo

How do I find the path of a template file using ERB?

I am using embedded ruby (ERB) to generating text files. I need to know the directory of the template file in order to locate another file relative to the template file path. Is there a simple method from within ERB that will give me the file name and directory of the current template file?
I'm looking for something similar to __FILE__, but giving the template file instead of (erb).
When you use the ERB api from Ruby, you provide a string to ERB.new, so there isn’t really any way for ERB to know where that file came from. You can however tell the object which file it came from using the filename attribute:
t = ERB.new(File.read('my_template.erb')
t.filename = 'my_template.erb'
Now you can use __FILE__ in my_template.erb and it will refer to the name of the file. (This is what the erb executable does, which is why __FILE__ works in ERB files that you run from the command line).
To make this a bit a bit more useful, you could monkey patch ERB with a new method to read from a file and set the filename:
require 'erb'
class ERB
# these args are the args for ERB.new, which we pass through
# after reading the file into a string
def self.from_file(file, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
t = new(File.read(file), safe_level, trim_mode, eoutvar)
t.filename = file
t
end
end
You can now use this method to read ERB files, and __FILE__ should work in them, and refer to the actual file and not just (erb):
t = ERB.from_file 'my_template.erb'
puts t.result

Require a ruby file in a ruby file

I want to require a file called config.rb in a different ruby file called basics.rb. I'm using Sinatra as my web framework. I'm sure there's a way to do this, I just can't find anything in the docs.
Hopefully it would look something like
post '/' do
require 'config.rb'
// logic
end
If config.rb is in your load path, you can require it at the top of your basics.rb file with require 'config'. If it is not in your load path, you'll need something like require '/path/to/your/config'.
The code you've posted will require the file. But only when someone POSTs to '/'.
Also, it's normal to omit the .rb extension when requiring ruby files. But you can include it if you like.
You can view your load path by inspecting the global variable $LOAD_PATH. From the command line ruby -e 'puts $LOAD_PATH' will print it for your version of ruby. You can also add directories to your load path.

Explain to me a Sinatra setup for dummy's for a preview of html/css code

A word of warning up front: I do not know even the ruby basics, but I'm trying to learn more and more of the world of shell scripting this year.
I saw this Vimeo video of Ben Schwarz and immediately thought that I'd like to use such a tool to debug my sass and haml files.
So this is a call to help me to grasp the concept of Sinatra.
What I want is a simple way to output the code of my index.html to check if all the haml magic was applied correctly - so it should function as a source viewer that gives me live updates. I'd prefer it if Sinatra simply looked at the files that LiveReload already rendered (c.f. index.html) in my project folder.
Update: This is a screenshot of the Vimeo Video. It shows just the raw CSS output of a Sass file. This is what I'd like to have for my Haml and Sass code, or better for the output files that are already rendered by LiveReload as HTML and CSS.
I looked at the source file from #benschwarz at his github, but I wasn't even with his own example I'm only getting the standard: "Sinatra doesn’t know this ditty." So transferring this to work with html is still out of my reach.
What I did so far:
I setup my project as usual in ~/Sites/projectname
I setup RVM and install all the gems I need
Sass, Compass, Haml - the output gets compiled via LiveReload
Sinatra
I created myapp.rb in ~/Sites/projectname with the following content:
# myapp.rb
require 'sinatra'
set :public_folder, '/'
get '/' do
File.read(File.join('public', 'index.html'))
end
Whatever, I fired up Sinatra and checked http://localhost:4567/ – this didn't work because I do not know how to set the public_folder to ~/Sites/projectname.
Afterthoughts:
So I went on to search the net, but my limited knowledge of Ruby put my attempt of an successful research to an immediate halt.
Here are some sites I stumpled upon which are obvioulsy close to the solution I need, but… like I told you in the first sentence: if the solution was a book, I'd need the "For Dummies" version.
https://bitbucket.org/sulab/genelist_store/src/30fc0ba390b9/idea8/idea8.rb
Serving static files with Sinatra
http://www.sinatrarb.com/intro
Obvioulsy the reference documentation of Sinatra would help me, but I don't speak the language, hence, I don't get the lingo.
About public folder:
The public_folder is relative to your app file myapp.rb. If you have a public folder inside the projectname folder, this is your public folder. If you have your css, js and image files in another folder, say, includes under project_name, then you need to change the line:
# Actually, you need to remove the line above from myapp.rb as it is.
# The line means that the public folder which is used to have css, js and
# image files under '/' and that means that even myapp.rb is visible to everyone.
set :public_folder, '/'
# to:
set :public_folder, File.dirname(__FILE__) + '/includes'
And that will serve up css, js and/or image files from the project_name/includes folder instead of project_name/public folder.
Reading the html file:
Reading the html files does not depend on the public folder settings. These need not be inside the public folder.
get '/' do
File.read(File.dirname(__FILE__) + '/index.html')
# This says that the app should read the index.html
# Assuming that both myapp.rb and index.html are in the same folder.
# incase the html files are inside a different directory, say, html,
# change that line to:
# File.read(File.dirname(__FILE__) + '/html/index.html')
# Directory structure sample:
# project_name
# | - myapp.rb
# | - index.html (and not html/index.html etc.)
# | /public (or includes incase the css, js assets have a different location)
# | | /css
# | | /js
# | | /images
end
To get the html output inside the browser
After the file is read, typically, this will be your string: "<html><head></head><body></body></html>"
Without escaping the string, the browser renders the html string as html (no pun) and that's why you won't see any text. To escape the html, you can use the CGI class provided by Ruby (hat tip). So, in the end, this will be your snippet:
get '/' do
CGI::escapeHTML(File.read(File.dirname(__FILE__) + 'index.html'))
end
But that will spit out the html file in a single line. To clean it up,
# myapp.rb
get '/' do
#raw_html = CGI::escapeHTML(File.read(File.dirname(__FILE__) + 'index.html'))
end
# Using inline templates to keep things simple.
# get '/' do...end gets the index.erb file and hence, in the inline template,
# we need to use the ## index representation. If we say get '/home' do...end,
# then the inline template will come under ## home. All the html/erb between
# two "##"s will be rendered as one template (also called as view).
# The <%= #raw_html %>spews out the entire html string read inside the "get" block
__END__
## index
<html>
<head></head>
<body>
<pre>
<%= #raw_html %>
</pre>
</body>
</html>
If you're trying to render an index.html file, I would try storing it in the /views directory with an .erb extension. Or use an inline template. Here is a great resource

Resources