Sinatra does not start with twitter gem - ruby

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

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!

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

Running rspec in Sinatra app just starts the server

I'm using rspec to test my Sinatra app. The app is super simple, and so are the tests, but when I run rspec from the CLI, it just starts the app server. I've never had this happen.
Here's what my spec_helper.rb looks like:
#spec/spec_helper.rb
require File.expand_path '../../app.rb', __FILE__
ENV['RACK_ENV'] = "test"
require 'rspec'
require 'rack/test'
set :environment, :test
set :run, false
set :raise_errors, true
set :logging, false
module RSpecMixin
def app
App.new
end
end
RSpec.configure do |config|
config.color_enabled = true
config.tty = true
config.formatter = :documentation
config.include Rack::Test::Methods
config.include RSpecMixin
end
And my spec is just
require 'spec_helper'
describe "My Sinatra Application" do
it "should allow accessing the home page" do
expect(1).to eq(1)
end
end
I can't get rspec to run.
What I've tried:
I've tried the recommendations in this Sinatra testing guide. Also the rspec Sinatra test recipe. In this blog post, the set :run, false looked promising, but no dice. Then I thought, I'll just define a rake task. Putting the rspec gem in the test group and setting the RACK_ENV to test. All these things just start the app server:
$ rake spec
[2014-03-08 22:06:38] INFO WEBrick 1.3.1
[2014-03-08 22:06:38] INFO ruby 2.0.0 (2013-02-24) [x86_64-darwin11.4.2]
== Sinatra/1.4.4 has taken the stage on 4567 for development with backup from WEBrick
[2014-03-08 22:06:38] INFO WEBrick::HTTPServer#start: pid=21538 port=4567
Halp?
Try removing the new() from your def app:
module RSpecMixin
def app
App
end
end
An other way to create your app for testing is something like this:
APP = Rack::Builder.parse_file('config.ru').first
module RSpecMixin
def app
APP
end
end
Obvious this works only if you use config.ru.
I found the answer. It's embarrassing, but I was switching back and forth between the modular and classic style deciding which I liked best, and I had left an errant App.run! call at the bottom of my app.rb file.

simpler way to test my simple Rack app?

i have a Rack app like this:
app = Rack::Builder.new do
map '/' do
# ...
end
map '/edit' do
# ...
end
end.to_app
How would i test it without long-tail installation/setup/learn process.
RSpec and minitest are really great, but i do not really want to learn nor setup them.
Is there something i cat just plug in and write/run tests right away in plain Ruby?
I want to write tests as simple as i wrote the app above, without advanced techniques and gotchas.
In KISS I Trust!
you can try Specular + Sonar bundle.
Specular is for writing tests anywhere you need them.
Sonar is a mock "browser" that communicate to your app, just like rack-test does, but with some unique features and simpler workflow.
Using them is as simple as:
...
app.to_app
Spec.new do
include Sonar
app(app)
get
check(last_response.status) == 200
# etc...
end
puts Specular.run
so you put your specs right beside your app and write tests quickly in plain Ruby, without having to learn anything.
see the full example running at CIBox
(if it does not run automatically, click Run button)
PS: writing Rack apps this way is kinda a pain.
You can try a mapper, like Appetite one.
so your app may look like this:
class App < Appetite
map :/
def index
'index'
end
def edit
'edit'
end
end
see the same example but with app built by Appetite here
Simplest? Use Rack::Test with Test::Unit. gem install rack-test and run with ruby filename.rb
require "test/unit"
require "rack/test"
class AppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Rack::Builder.new do
map '/' do
run Proc.new {|env| [200, {'Content-Type' => 'text/html'}, "foo"] }
end
map '/edit' do
# ...
end
end.to_app
end
def test_index
get "/"
assert last_response.ok?
end
end
Update: RSpec style requested - gem install rspec; run with rspec filename.rb
require 'rspec'
require 'rack/test'
describe 'the app' do
include Rack::Test::Methods
def app
Rack::Builder.new do
map '/' do
run Proc.new {|env| [200, {'Content-Type' => 'text/html'}, "foo"] }
end
map '/edit' do
# ...
end
end.to_app
end
it 'says foo' do
get '/'
last_response.should be_ok
last_response.body.should == 'foo'
end
end
You could use rack-test but that again entails using minitest/unit test but is the most common way testing Rack apps.

How do I configure RSpec with Sinatra to dynamically determine which Sinatra app is running before my test suite runs?

Ok so. I'm wanting to do request specs with RSpec for my Sinatra app.
I have a config.ru
# config.ru
require File.dirname(__FILE__) + '/config/boot.rb'
map 'this_route' do
run ThisApp
end
map 'that_route' do
run ThatApp
end
The boot.rb just uses Bundler and does additional requires for the rest of the app:
ThisApp looks like:
# lib/this_app.rb
class ThisApp < Sinatra::Base
get '/hello' do
'hello'
end
end
So I'm using RSpec and I want to write request specs like:
# spec/requests/this_spec.rb
require_relative '../spec_helper'
describe "This" do
describe "GET /this_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
This works fine because my spec_helper.rb is setup as follows:
# spec/spec_helper.rb
ENV['RACK_ENV'] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/boot")
require 'capybara/rspec'
RSpec.configure do |config|
config.include Rack::Test::Methods
end
def app
ThisApp
end
But my problem is that I want to test "ThatApp" from my rackup file along with any amount more apps I might add later along with "ThisApp". For example if I had a second request spec file:
# spec/requests/that_spec.rb
require_relative '../spec_helper'
describe "That" do
describe "GET /that_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
RackTest requires the rack app I'm testing be defined in the spec_helper file with that 'app' method, and I think eventually I'm going to have to feed Capybara.app the same thing as well when doing further request specs with it.
I feel like I'm missing something and maybe there's an easy way to setup 'app' for RackTest and Capybara at runtime depending on what route and consequent rack app I'm testing in my request specs. Like a before filter in RSpec.configure maybe, but I can't think of or find how I'd access what rack app is currently loaded and try and set it there before the test suite runs.
Anyone get what I'm trying to do and can think of something? Thanks for any help.
Define a different helper module for each sinatra app you want to test, each of which should define its own app method that returns the corresponding app. Then you can simply include MySinatraAppHelper in the appropriate example groups where you want to test the the given app.
You can also use rspec metadata to have the module included in example groups automatically.
Have a look at my sinatra-rspec-bundler-template. Especially at the spec files. I think that's what you are trying to achieve.
It combines two separate Sinatra apps each with it's own specs.

Resources