Calling a Sinatra app instance method from TestCase

痴心易碎 提交于 2019-11-30 18:27:02

Sinatra aliases the new method to new! before redefining it, so the simplest solution is to use that instead:

def app
  MyApp.new!
end

Of course I only noticed that after I’d come up with the following, which I’ll leave in as it could be useful/informative.


A possible way to get round Sinatra redefining the new method and returning a complete Rack app a get hold of an instance your actual base class is to do what the “real” new method does yourself:

def app
  a = MyApp.allocate
  a.send :initialize
  a
end

This is a bit of a hack, but it might be useful for testing.

Another technique would be to “walk” the middleware stack until you got to your class. The following is a little fragile, as it depends on all the middleware involved to use the name @app to refer to the next app in the stack, but this is fairly common.

def app
  a = MyApp.new
  while a.class != MyApp
    a = a.instance_variable_get(:@app)
  end
  a
end

That won’t work on the yet to be released Sinatra 1.4 though (at least not on the current master, which is commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12), as new now returns a Wrapper class and the loop never ends. In this case you can grab the base class directly from the @instance variable:

def app
  MyApp.new.instance_variable_get :@instance
end

(note this last technique may well change before the final 1.4 release).

The problem you are encountering is, that MyApp.new does not return an instance of MyApp but an instance of the middleware wrapping your App (usually Rack::Head or Sinatra::ShowExceptions). A good explanation can be found in the thread Sinatra Usage Question / Rack App.

The only solution I can think of is to change your instance method to a class method which can be called without the instance itself. As the instance of your App may be freshly instantiated for every request, an instance method probably doesn't have much advantages over a class method in your scenario.

Edit:

In the upcoming Sinatra 1.4 the initialization will change. Sinatra::Base.new will return a Sinatra::Wrapper instance, which exposes #settings and #helpers. This may help solve the problem of accessing Sinatra::Base instance methods. See the Sinatra Changelog for more information.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!