With Ruby + Webrick + Sinatra, where does 'development?' method come from? - ruby

Where does the concept of 'development mode' come from when using ruby + webrick + sinatra?
require 'sinatra'
require 'sinatra/reloader'
get '/test' do
development?.to_s
end
When I run the above app by 'ruby test.rb -p 3000' http://localhost:3000/test returns "true" ... but why does it return true? Is development mode a ruby, webrick, rack or sinatra concept? Also, is this functionality documented anywhere in particular in a non-rails specific manner? I'm finding many people reference the concept of development mode, but I've been surprised by how hard it has been to find relevant information ... maybe I'm just not google-ing the right keywords ...

Sinatra's source code (base.rb) shows these 3 definitions:
def development?; environment == :development end
def production?; environment == :production end
def test?; environment == :test end
So those true/false methods are based on the set environment. Sinatra defaults to run in development mode unless you tell it otherwise (when you start a Sinatra app, you'll see something like
== Sinatra/1.2.6 has taken the stage on 4567 for **development** with backup from WEBrick".
To tell it to run in production, you would do this:
ruby test.rb -p 3000 -e production

Related

How to pass Puma::Configuration to Sinatra?

This is my web app:
class Front < Sinatra::Base
configure do
set :server, :puma
end
get '/' do
'Hello, world!'
end
end
I start it like this (don't suggest to use Rack, please):
Front.start!
Here is my configuration object for Puma, which I don't know how to pass to it:
require 'puma/configuration'
Puma::Configuration.new({ log_requests: true, debug: true })
Seriously, how?
Configuration is tightly connected to a way in which you run puma server.
The standard way to run puma - puma CLI command. In order to configure puma config file config/puma.rb or config/puma/<environment>.rb should be provided (see example).
But you asked how to pass Puma::Configuration object to puma. I wonder why you need it but AFAIK you need to run puma server programmatically in your application code with Puma::Launcher(see source code)
conf = Puma::Configuration.new do |user_config|
user_config.threads 1, 10
user_config.app do |env|
[200, {}, ["hello world"]]
end
end
Puma::Launcher.new(conf, events: Puma::Events.stdio).run
user_config.app may be any callable object (compatible with Rack interface) like Sinatra application.
Hope it's helpful.
Do you want to pass exactly an object or just a configuration in general? For the last option it's possible, but Puma will not log anything anyway (I'm not sure, but seems like you worry exactly about logging settings for Puma).
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/inline'
gemfile(true) do
gem 'sinatra'
gem 'puma'
gem 'openssl'
end
require 'sinatra/base'
class Front < Sinatra::Base
configure do
set :server, :puma
set :server_settings, log_requests: true, debug: true, environment: 'foo'
end
get '/' do
'Hello, world!'
end
end
Front.start!

How to use get programatically current host from heroku and use it in rspec test?

I'm writting a simple web app (sinatra) thats does github authentication.
I have to make a create a link with a callback param, somethig like: https://github.com/login/oauth/authorize?client_id=b5b1a33df1c7b5acccac&redirect_uri=http://localhost:4567/step2callback&scope=public_repo,user,gist,admin:repo_hook,gist, so that when the uses click on it it will authenticate, authorize my application, then send the user back to my web app.
Since i'm using rspec, I would like to make a code that pass on tests and on production, so I would like to get the current host+port to use it on the code I generate the link, something like:
HOST = get_current_host # this is the problem, how to get it?
#authorize_url = #client.authorize_url(#client.client_id,
{
:redirect_uri => "#{HOST}/step2",
:scope => 'public_repo,user,gist,admin:repo_hook,gist'
})
So, my question is how do I get my current running host on heroku, so my code would work on test and production?
You can configure different values for different environments
A simple example given below:
# File: test.rb
require 'sinatra'
# Set the values of various host names based on deployment environment
configure(:production) { set :host, "production-host" }
configure(:development) { set :host, "development-host" }
configure(:test) { set :host, "test-host" }
get '/' do
"Hi #{settings.host}"
end
Set RACK_ENV environment variable to environment value - production, development, or test
>set RACK_ENV=test
Run the Sinatra App
>ruby test.rb
[2015-12-17 20:20:46] INFO WEBrick 1.3.1
[2015-12-17 20:20:46] INFO ruby 2.1.7 (2015-08-18) [x64-mingw32]
== Sinatra (v1.4.6) has taken the stage on 4567 for test with backup from WEBrick
[2015-12-17 20:20:46] INFO WEBrick::HTTPServer#start: pid=11040 port=4567
Access the URL:
>curl http://localhost:4567
Hi test-host
If you are using Rack to run your Sinatra app, you could have following as config.ru
# config.ru
require 'sinatra'
require './test.rb'
configure(:production) { set :host, "production-host" }
configure(:development) { set :host, "development-host" }
configure(:test) { set :host, "test-host" }
run Sinatra::Application
In this case, test.rb will be simplified like below:
# test.rb
require 'sinatra'
get '/' do
"Hi #{settings.host}"
end
You can specify the environment on command line as shown below:
> rackup -E test config.ru
This answer is inspired from Sinatra configuring environments on the fly

Sinatra exits without error

I'm very new to Sinatra, and I'm trying to get asset management & compiling working according to this article. Here is my main file so far:
require 'sinatra/base'
require 'sinatra/assetpack'
require 'sass'
class App < Sinatra::Base
register Sinatra::AssetPack
assets do
css :application, [
'/css/main.scss'
]
css_compression :sass
end
get '/hi' do
erb "Hello World!"
end
end
but, for some reason, when I run ruby main.rb, it just exits without failure or anything. Is there a special keyword to get the application to serve files?
Using the modular style of Sinatra application, as you are doing, running ruby main.rb is going to exit without error because it is being treated as a standard ruby application and no webserver is ever created.
You have two options.
1 Add run! if app_file == $0 just before the final end statement in your example.
This will allow you to run the app with ruby main.rb
2 (This is the preferred method) Create a rackup file config.ru with the following contents.
require './main.rb'
run App
Now you can serve the application with the command rackup -p 4567 where 4567 is whatever port number you want to use.
You need to start the application
require 'sinatra/base'
require 'sinatra/assetpack'
require 'sass'
class App < Sinatra::Base
register Sinatra::AssetPack
assets do
css :application, [
'/css/main.scss'
]
css_compression :sass
end
get '/hi' do
erb "Hello World!"
end
run! if app_file == $0
end
one observation, erb should point to a template, example:
get '/hi' do
erb :home
end
should look for a file in ../views/home.erb
Also Assuming you already did gem install sinatra. I would also use the rerun gem while developing in sinatra, gem install rerun then rerun ruby app.rb. Rerun will reload your project when you make changes to your code so you won't have to restart the app when ever you make a change.

Why do I need to run my sinatra app again when making changes and my environment is not :development?

I just implemented Compass configuration for my Sinatra app but when I change the environment to :test or :production and modify my files like screen.sass or index.haml my changes are not reflected when I reload the page so I need to run my app again?
Is it normal? Is is just me?
This is how my app.rb file looks like:
require 'sinatra'
require 'haml'
require 'sass'
require 'compass'
require './helpers.rb'
configure do
set :environment, :test
Compass.configuration do |config|
settings.environment == :production ?
config.output_style = :compressed :
config.output_style = :nested
settings.environment == :development ?
config.line_comments = true :
config.line_comments = false
end
set :sass, Compass.sass_engine_options
end
before do
#js = 'javascript:;'
end
get '/scripts/jquery.js' do
# Downloads the latest jQuery 1.x version when needed. Requires to reload the page after done.
`curl "https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" >> public/scripts/jquery.js`
end
get '/styles/:name.css' do
sass :"styles/#{params[:name]}"
end
get '/?' do
haml :index
end
get '/:page/?' do
haml params[:page].to_sym
end
Any idea?
Generally, if you make a change to a running Sinatra application, you have to restart the application, as the program has already been loaded to memory.
There are options for automatically detecting changes and restarting the application on the Sinatra FAQ.
Since Shotgun fix the issue partially (reloading the files for your at production, maybe try with Sinatra::Reloader which, IMHO, works better than Shotgun.
Maybe something like (not tested)
require "sinatra"
configure(:production) do |c|
require "sinatra/reloader"
c.also_reload "*.sass", "*.haml"
end
That being said, are you sure you do need this kind of behavior on a production/test environment for updating? Development env. should be (at least, for what I use it for) for this kind of hot testing.
I used to use sinatra::reloader
but I didn't like the huge dependencies incurred (as should we all be mindful how many gems get activated)
pistol ( at a tender age of ver 0.0.2) and I think does the required job nicely
I use shotgum gem for this.
gem install shotgun
then
shotgun app.rb
from within the app dir
this then reloads the app per request, rather than holding the whole thing in memory. you access the site on localhost:9393

Reloading Sinatra app on every request on Windows

I've set up Rack::Reload according to this thread
# config.ru
require 'rubygems'
require 'sinatra'
set :environment, :development
require 'app'
run Sinatra::Application
# app.rb
class Sinatra::Reloader < Rack::Reloader
def safe_load(file, mtime, stderr = $stderr)
if file == Sinatra::Application.app_file
::Sinatra::Application.reset!
stderr.puts "#{self.class}: reseting routes"
end
super
end
end
configure(:development) { use Sinatra::Reloader }
get '/' do
'foo'
end
Running with thin via thin start -R config.ru, but it only reloads newly added routes. When I change already existing route, it still runs the old code.
When I add new route, it correctly reloads it, so it is accessible, but it doesn't reload anything else.
For example, if I changed routes to
get '/' do
'bar'
end
get '/foo' do
'baz'
end
Than / would still serve foo, even though it has changed, but /foo would correctly reload and serve baz.
Is this normal behavior, or am I missing something? I'd expect whole source file to be reloaded. The only way around I can think of right now is restarting whole webserver when filesystem changes.
I'm running on Windows Vista x64, so I can't use shotgun because of fork().
You could try sinatra-reloader, which is known to work well on Windows (also, it's faster than shotgun).
This works:
# config.ru
require 'rubygems'
require 'app'
set :environment, :development
run Sinatra::Application
# app.rb
require 'sinatra'
class Sinatra::Reloader < Rack::Reloader
def safe_load(file, mtime, stderr = $stderr)
if file == File.expand_path(Sinatra::Application.app_file)
::Sinatra::Application.reset!
stderr.puts "#{self.class}: reseting routes"
end
super
end
end
configure(:development) { use Sinatra::Reloader }
get '/' do
'foo'
end
It matters from where you have the require statement. But I find the following solution more elegant and robust:
# config.ru
require 'rubygems'
require 'sinatra'
require 'rack/reloader'
require 'app'
set :environment, :development
use Rack::Reloader, 0 if development?
run Sinatra::Application
# app.rb
Sinatra::Application.reset!
get '/' do
'foo'
end
Does Shotgun not work on Windows?
From the README:
Shotgun
This is an automatic reloading version of the rackup command that's shipped with
Rack. It can be used as an alternative to the complex reloading logic provided
by web frameworks or in environments that don't support application reloading.
The shotgun command starts one of Rack's supported servers (e.g., mongrel, thin,
webrick) and listens for requests but does not load any part of the actual
application. Each time a request is received, it forks, loads the application in
the child process, processes the request, and exits the child process. The
result is clean, application-wide reloading of all source files and templates on
each request.
You can also try using Trinidad a JRuby Rack container based on Tomcat. In my experience it does change reloading by default without having to modify your source files. Bloody fast too. Obviously no good if you are using native libraries, but if you are deploying on Windows you are probably used to adopting a pure-ruby approach.
Its syntax is just as simple as the thin approach:
jruby -S trinidad -r config.ru
There is no Java specific yak shaving (i.e. creating web.xml or WARing up your Ruby app) and the gem is simple to install.

Resources