How to pass Puma::Configuration to Sinatra? - ruby

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!

Related

Sinatra Heroku app: `start_server': undefined method `run' for HTTP:Module (NoMethodError) [duplicate]

when i try to start sinatra, i'm getting following error
/var/lib/gems/1.9.1/gems/sinatra-1.4.4/lib/sinatra/base.rb:1488:in start_server': undefined methodrun' for HTTP:Module (NoMethodError)
require 'sinatra/base'
require_relative "twt.rb"
class SinatraApp < Sinatra::Base
set :static, true
set :public_folder, File.dirname(__FILE__) + '/static'
get '/getuserinfo' do
#user = twit.getuserinfo
erb :userInfo
end
end
SinatraApp.run!
in "twt.rb" i require twitter (5.7.1)
require 'twitter'
class Twit
attr_accessor :client
def initialize(consumer_key,consumer_secret,access_token,access_token_secret)
#client = Twitter::REST::Client.new do |config|
config.consumer_key = consumer_key
config.consumer_secret = consumer_secret
config.access_token = access_token
config.access_token_secret = access_token_secret
end
end
def getUserInfo
return user = {
"name"=> client.current_user.name,
"id" => client.current_user.id
}
end
def showAllFriends
client.friends.each { |item| puts item.name }
end
def showFollowers
client.followers.each { |item| puts item.screen_name }
end
def showAllTweets
client.user_timeline.each {|item| puts item.text}
end
def showAllUserTweets(userScreenName)
client.user_timeline(userScreenName).each {|item| puts item.text}
end
def sendTweet(content)
client.update(content)
end
end
if i remove require_relative "twt.rb" line sinatra works fine.
When you run a Sinatra app using the built-in web server (as you do with SinatraApp.run!), Sinatra tries to determine which server to use by checking a list of servers in turn to see which is available. The actual list depends on the version of Ruby you are using, but one server that it always checks is net-http-server, which is simply named HTTP.
The way Sinatra checks for the availability of a server is by using a rack method that calls const_get to try and find the constant Rack::Handler::<server-name>. However, due to the way const_get works, if that constant is not available, but a top level constant with the same name as server-name is, then that will be returned, whatever class it is. (This is arguably a bug in Rack).
The Twitter gem depends on the http gem, and that in turn defines a HTTP module. (Naming a top-level module with something as generic as HTTP is arguably not a good idea).
So what is happening in this case is Sinatra is checking to see if the HTTP server is available, but Rack is returning the HTTP module from the http gem, which isn’t a server. Not being a Rack server it doesn’t have a run method, so when Sinatra tries to use it as one you get the error start_server': undefined method `run' for HTTP:Module.
One workaround is not to use the built-in server, such as the way you have discovered using a config.ru file and starting the app with rackup.
Another solution is to explicitly specify the server to use in your Sinatra app. For example you could install Thin, and then use:
set :server, 'thin'
In fact simply installing Thin would be sufficient as Thin is searched for before HTTP, but you are probably better explicitly setting the server to use. If you cannot install any other server for any reason you could use Webrick instead:
set :server, 'webrick'
i found the solution.
i launch sinatra with config.ru and it works now.
rack config.ru

How to start a minimal ruby app using Puma or Unicorn?

I have a very basic ruby example running on Thin, but I would like to know how to translate this example to use Unicorn or Puma as the HTTP server instead. Here is the code I have now:
require 'rack'
class HelloWorld
def talk()
return "Hello World!"
end
end
class SomeServer
def start(server_object, port)
app = proc do |env|
[ 200, {"Content-Type" => "text/html"}, [server_object.talk()] ]
end
Rack::Handler::Thin::run(app, :Port => port)
end
end
SomeServer.new.start(HelloWorld.new, 3000)
This runs fine and well, but I cannot figure out how to make it run using Puma or Unicorn instead. Most online documentation I find for the two is for Rails apps. How can I utilize the multi-threading capabilities of these servers with this simple program?
use sinatra.
So to take it step by step first install sinatra and puma gems
gem install sinatra
gem install puma
then create a file myapp.rb
require 'sinatra'
configure { set :server, :puma }
get '/' do
"Hello World!"
end
then run the file
ruby myapp.rb
by default sinatra listens on 4567 so go to localhost:4567
you can configure puma to listen on a specific port or do a lot of other things using a config file read the documentation
A minimal example that doesn't require additional gems looks like this.
Using a single file
Create a puma config file config.rb with the following content:
app do |env|
body = 'Hello, World!'
[200, { 'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }, [body]]
end
bind 'tcp://127.0.0.1:3000'
and run puma with
puma -C /path/to/config.rb
That's it.
Using a configuration and a rackup file
In the example above, the config file contains the application itself. It makes sense to move the application to a rackup file: Create a rackup file app.ru with the following content:
class HelloWorld
def call(env)
body = 'Hello, World!'
[200, { 'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }, [body]]
end
end
run HelloWorld.new
Then update your config.rb, removing the app and linking the rackup file instead:
rackup '/path/to/app.ru'
bind 'tcp://127.0.0.1:3000'
and run puma as before with
puma -C /path/to/config.rb
The example configuration file for puma is helpful. (Update: This example configuration file is no longer maintained. The authors refer to dsl.rb instead.)
Instead of starting your app with Rack::Handler::Thin, you should be able to use the Puma Rack handler instead, like this:
Rack::Handler::Puma.run(app, :Port =>port)
You'd need to also require 'rack/handler/puma' after installing the Puma gem.

Sinatra does not start with twitter gem

when i try to start sinatra, i'm getting following error
/var/lib/gems/1.9.1/gems/sinatra-1.4.4/lib/sinatra/base.rb:1488:in start_server': undefined methodrun' for HTTP:Module (NoMethodError)
require 'sinatra/base'
require_relative "twt.rb"
class SinatraApp < Sinatra::Base
set :static, true
set :public_folder, File.dirname(__FILE__) + '/static'
get '/getuserinfo' do
#user = twit.getuserinfo
erb :userInfo
end
end
SinatraApp.run!
in "twt.rb" i require twitter (5.7.1)
require 'twitter'
class Twit
attr_accessor :client
def initialize(consumer_key,consumer_secret,access_token,access_token_secret)
#client = Twitter::REST::Client.new do |config|
config.consumer_key = consumer_key
config.consumer_secret = consumer_secret
config.access_token = access_token
config.access_token_secret = access_token_secret
end
end
def getUserInfo
return user = {
"name"=> client.current_user.name,
"id" => client.current_user.id
}
end
def showAllFriends
client.friends.each { |item| puts item.name }
end
def showFollowers
client.followers.each { |item| puts item.screen_name }
end
def showAllTweets
client.user_timeline.each {|item| puts item.text}
end
def showAllUserTweets(userScreenName)
client.user_timeline(userScreenName).each {|item| puts item.text}
end
def sendTweet(content)
client.update(content)
end
end
if i remove require_relative "twt.rb" line sinatra works fine.
When you run a Sinatra app using the built-in web server (as you do with SinatraApp.run!), Sinatra tries to determine which server to use by checking a list of servers in turn to see which is available. The actual list depends on the version of Ruby you are using, but one server that it always checks is net-http-server, which is simply named HTTP.
The way Sinatra checks for the availability of a server is by using a rack method that calls const_get to try and find the constant Rack::Handler::<server-name>. However, due to the way const_get works, if that constant is not available, but a top level constant with the same name as server-name is, then that will be returned, whatever class it is. (This is arguably a bug in Rack).
The Twitter gem depends on the http gem, and that in turn defines a HTTP module. (Naming a top-level module with something as generic as HTTP is arguably not a good idea).
So what is happening in this case is Sinatra is checking to see if the HTTP server is available, but Rack is returning the HTTP module from the http gem, which isn’t a server. Not being a Rack server it doesn’t have a run method, so when Sinatra tries to use it as one you get the error start_server': undefined method `run' for HTTP:Module.
One workaround is not to use the built-in server, such as the way you have discovered using a config.ru file and starting the app with rackup.
Another solution is to explicitly specify the server to use in your Sinatra app. For example you could install Thin, and then use:
set :server, 'thin'
In fact simply installing Thin would be sufficient as Thin is searched for before HTTP, but you are probably better explicitly setting the server to use. If you cannot install any other server for any reason you could use Webrick instead:
set :server, 'webrick'
i found the solution.
i launch sinatra with config.ru and it works now.
rack config.ru

Sinatra, modular style. What did I do wrong?

I use Sinatra modular style, i don't know what going bad. I serach google but didn't find anything
require 'sinatra/base'
class App < Sinatra::Base
get '/' do
haml '%h1 Test'
end
end
run App
And a see test.rb:12:in <main>': undefined methodrun' for main:Object (NoMethodError)
What going wrong?
did you run it via ruby -rubygems hi.rb (assuming this code is in hi.rb). If so, you don't need run App. Unless you are running it through another framework built on/with Sinatra.
Also might want to include haml...
You have a config.ru:
# config.ru
require 'my_app'
run MyApp
and a my_app.rb:
# my_app.rb
require 'sinatra/base'
require 'haml'
class MyApp < Sinatra::Base
get('/') { haml '%h1 Test' }
# start the server if ruby file executed directly
run! if app_file == $0
end
then in the folder where the my_app.rb is run this to start the app on localhost:4657:
rackup -p 4567
Regarding the comment above where the error below is displayed:
`start_tcp_server': no acceptor (RuntimeError)
This appears when you are trying to bind to an already bound port. Trying a different port number should resolve.

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