Running Sinatra inside a Ruby Gem Tweet
This is a post in the Picky series on its workings. If you haven’t tried it yet, do so in the Getting Started section. It’s quick and painless :)
In this post I’ll show how to have Sinatra run directly from inside a gem. And at the end, how Picky uses this for its advantage.
Let’s go singing in the gem!
The thing is…
What I wanted, was to add a nice statistics web interface to Picky.
First I though about adding it to the server, but soon after (~1.2µs) decided that this was a silly idea.
Picky is heavily designed around loosely connected elements in the server. I think this is even a better idea outside of a large component such as a server. So what I found myself thinking about – while showering – next was, to have a gem which generates a Sinatra application…
Suddenly the room lit up and I spotted, scrawled on the wall in burning letters of blood:
The wrong question.
I gave it not much thought, as it can get crazy in this part of Zürich. Then, while gorging myself on my beloved alphabet soup, and thinking about how to structure files in this web application exactly, the letters suddenly formed a sentence:
Dude the wrong, fucking question.
(Soups can only spell so well)
I only got it a few hours later, while three swedish massage therapists kneaded my shoulders.
In computer science, the answers aren’t nearly as important as asking:
…the right fucking question.
The right fucking question
The right question is:
How do I fit a web application wholly in a gem, such that I can do a
$ picky stats log/search.log
on any Picky logfile and it will parse it and show me a nice statistical representation of it in a browser without soiling the directory and everything else?
The right fucking tool for the job
That’s Sinatra I’m talking about. The great and extremely easy to use Ruby DSL for web applications.
Give it a whirl if you haven’t seen it!
How to do it
First, set up a gem structure – let’s call the gem “rain_sining”. Then, inside it, set up the following structure:
rain_singing
/bin
/lib
/rain_singing
/application # <- the app is in here
app.rb # <- the webapp itself
/images
/javascripts
/stylesheets
/views
rain_singing.rb
rain_singing.gemspec
/spec
The “hardest” thing is getting the directories correctly set up.
So what you do inside app.rb
is:
require 'sinatra'
require 'haml' # if you use haml views
class SingingRain < Sinatra::Base
set :static, true # set up static file routing
set :public, File.expand_path('..', __FILE__) # set up the static dir (with images/js/css inside)
set :views, File.expand_path('../views', __FILE__) # set up the views dir
set :haml, { :format => :html5 } # if you use haml
# Your "actions" go here…
#
get '/' do
haml :'/index'
end
end
# Run the app!
#
puts "Hello, you're running your web app from a gem!"
SingingRain.run!
And that’s already it for the app.
Now, if you want to define a binary for the gem, put an executable rain_singing
file into /bin
. Into this file you’d write:
#!/usr/bin/env ruby
#
begin
require 'rain_singing/application/app.rb'
rescue LoadError => e
require 'rubygems'
path = File.expand_path '../../lib', __FILE__
$:.unshift(path) if File.directory?(path) && !$:.include?(path)
require 'rain_singing/application/app.rb'
end
Then, we need to tell rubygems that this gem has an executable:
Gem::Specification.new do |s|
...
s.executables = ['rain_singing']
s.default_executable = 'rain_singing'
...
end
After generating your gem with
$ gem build rain_singing.gemspec
and installing it with
$ gem install rain_singing-1.0.0.gem
you are ready to run
$ rain_singing
Hello, you're running your web app from a gem!
Good stuff. Good stuff. Makes me want to sing in the rain.
In Picky
Picky uses this for two things.
A statistics interface ($ gem install picky-statistics
), run
$ picky stats path/to/your/search.log 1234
or the live interface to the running server ($ gem install picky-live
), run
$ picky live localhost:8080/admin 1234
You need to add route %r{/admin} => LiveParameters.new
in the server to have it work. But then you get the interface described in this blog post.
Nice, eh?
Conclusions
So we’ve seen
- that Sinatra rocks my noodles
- that a Gem can contain a whole webapp without footprint
- that Picky uses both for maximal profit!
Hope you learnt something new :)
Next A better Rubygems searchShare
Previous Parslet Intro