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

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

Related

HAML::Engine, image is not rendering

I am using just Ruby (no rails) to make a gem that takes a yaml file as an input an it produces a pdf.
I am using pdfKit and Haml. In the haml file I need to render an image. When using pure HTML, PDFKit shows the image, but when using Haml::Engine and the haml file the image doesn't get rendered.
I have put the image, the .module and the haml file under one folder to make sure the issue is not the path.
In my gemspec I have the following
.
.
gem.add_development_dependency("pdfkit", "0.8.2")
gem.add_development_dependency("wkhtmltopdf-binary")
gem.add_development_dependency("haml")
The HTML that works:
<html>
<head>
<title>
junk
</title>
</head>
<body>
HI
<img src="watermark.png"/>
Bye
</body>
</html>
Haml version that doesn't work:
%html
%head
%title
junk
%body
HI
= img "watermark.png"
Bye
module:
require "pdfkit"
require "yaml"
require "haml"
require "pry"
.
.
junk = Haml::Engine.new(File.read("lib/abc/models/junk.haml")).render
kit2 = PDFKit.new(junk)
kit2.to_file("pdf/junk.pdf")
when using the html file, pdf renders the image, however, when I use the haml this is now my pdf looks like
and If I use
%img(src="watermark.png")
I get the following error when pdf is generated
Exit with code 1 due to network error: ContentNotFoundError
The PDF still gets generated, but the still looks like the image above.
So I am trying to see without using any rails, and img_tag, image_tag etc.. how would I just use the %img in haml file to render the proper image
Following is the output of junk, when I create #img = "watermark.png"
1 pry(DD)> junk
=> "<html>\n<head>\n<title>\njunk\n</title>\n</head>\n<body>\nHI\n<img src='watermark.png'>\nBye\n</body>\n</html>\n"
Replace the img tag %img(src=#img) still same result
I think this is not HAML issue, but wkhtmltopdf thing. Apparently it's not very good at handling relative urls to images. It should work with absolute path, for example:
%img(src="/home/user/junk/watermark.png")
To create an image tag in HAML you will need to use
%img(src="foo.png")
# or
%img{src: "foo.png"}
If you use
= img "watermark.png"
then you are calling the img method (if it exists), passing it "watermark.png" as argument and outputting the return value of that method in the generated HTML.
Honestly i'm not sure how that HTML template should work, when the HAML template that generates the same HTML does not. So I guess you run that script from different directories or so?
Anyways: Problem is, that you will need absolute paths for your files. Otherwise wkhtmltopdf will not be able to resolve your images.
You can use File.expand_path (see sample) for this, or write a custom helper.
I tried following:
Created two files:
/tmp/script.rb
/tmp/watermark.png
/tmp/template.haml
Where watermark.png is a screenshot I took from this question, script.rb is:
require "pdfkit"
require "haml"
template = File.read("template.haml")
html = Haml::Engine.new(template).render
File.write("template.html", html)
pdf = PDFKit.new(html)
pdf.to_file("output.pdf")
And template.haml is:
%html
%head
%title Something
%body
BEFORE
%img(src="#{File.expand_path(__dir__, "watermark.png")}")
AFTER
When I run this script like:
ruby-2.5.0 tmp$ ruby script.rb
Then the HTML that is generated is:
<html>
<head>
<title>Something</title>
</head>
<body>
BEFORE
<img src='/tmp/watermark.png'>
AFTER
</body>
</html>
And the generated PDF looks like:

Dynamic require_relative in test_helper not working

I've been battling for an hour with a require_relative in my test_helper.rb that I just can't seem to get to work.
Given a project structure like so
lib
|-- square_digits.rb
test
|-- test_square_digits.rb
|-- test_helper.rb
And these test files:
# test/test_square_digits.rb
require 'test_helper'
# test/test_helper.rb
require "minitest/autorun"
Dir.glob('../lib/**/*.rb').each { |f| require_relative f }
# require_relative "../lib/square_every_digit.rb"
I cannot get my tests to run correctly with the dynamic require, but directly requiring with the hardcoded path does function as intended, though the Dir.glob does seem to catch the file (while running pry in test/)
$ pry(main)> Dir.glob('../lib/**/*.rb')
$ => ["../lib/square_every_digit.rb"]
I have tried the require_relative gem, Dir[] and various solutions to no avail...
Have you tried generating the lines of code and using eval
baseDir = __dir__+"/RGSS Classes"
fileCol = Dir.children(baseDir)
fileCol.each do |library|
libPath = baseDir+"/"+library
code = "require '"+libPath+"'"
puts code
eval(code)
end
you wont be able to use require_reletive because it'll give a "LoadError: cannot infer basepath", i am unsure if it's the same reason as stated in this answer but using require worked
first need to get the current file location using __dir__ and then append whatever subfolder the files you want to require are. then you loop though the results generating the line of code for each file (i choose to generate the path in a variable first before adding it to the code)
obviously since eval is executing string as code if this is used outside of personal private use you'd might want to add some sanitization to the file names as a bad or maliciously named file will execute as code.
alternatively you can forgo using eval and have it output each line to a .rb file which you would then require which eliminates the risk of filenames being used to inject code

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

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.

Error reading local file in Sinatra

I'm trying to write a Sinatra app that reads in a list from a file, and then spits back a random item from that list.
I'm having trouble figuring out the path to the file to read it, though. Sinatra says 'no such file or directory' when I try to load an item in my browser:
Errno::ENOENT at /wod
No such file or directory - http://localhost:4567/listing.txt
Here is the code:
require 'sinatra'
#list
get /item
puts read_list[rand(#list.size)]
end
def read_list
File.open('listing.txt', 'r').readlines
end
I have the file in /public, which the Sinatra README says is the default location for hosting static files. Furthermore, if I put it in /public I can navigate to localhost:4567/listing.txt and read the file in the browser.
A couple things I noticed:
get /item
isn't correct, it should be:
get '/item' do
If you start your code inside the same directory the Ruby code is in, the current working-directory will be ".", which is where Ruby will look when trying to:
File.open('listing.txt', 'r').readlines
Ruby will actually use './listing.txt' as the path. That's OK if you manually launch the code from the root directory of the application, but that doesn't work well if you try to launch it from anywhere else.
It's better to be explicit about the location of the file when you're actually trying to load something for use with a web server. Instead of relying on chance, there are a couple things you can do to help make it more bullet-proof. Consider this:
def read_list
running_dir = File.dirname(__FILE__)
running_dir = Dir.pwd if (running_dir == '.')
File.open(running_dir + '/public/listing.txt', 'r').readlines
end
File.dirname gets the path information from __FILE__, which is the absolute path and name of the current file running. If the application was started from the same directory as the file, that will be ., which isn't what we want. In that case, we want the absolute path of the current working-directory, which Dir.pwd returns. Then we can append that to the path of the file you want, from the root of the application.
You'll need to do File.read('public/listing.txt', 'r') to get what you want here.
File.open isn't part of Sinatra and doesn't know to look in a specific place for static files, so it just looks in the current working directory.

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.

Resources