问题
I have been having an issue with missing instances and nilClass errors when calling my routes. After delving around within the source it seems like the generate_method call basically creates a new method using the block of the initial method.
get "/" do
@some_local_instance.do_something()
end
So in the above method there could very well be a local variable within that class called some_local_instance, however when the rote is actually evaluated it has no context as to where the method was defined, so it will fail.
The reason I ask is because as part of my script I have external classes which are loaded when Sinatra is loaded which register routes and when those routes are called I need to access some local variables on these classes. An example would be:
class SomeRouteClass
def initialize(sinatra, calculator)
@calculator = calculator
@sinatra = sinatra
end
def setup_routes
@sinatra.get "/add" do
return @calculator.add(1,1)
end
end
end
class Calculator
def add(a,b)
return a+b;
end
end
sinatra = Sinatra.new
calculator = Calculator.new
routing_class = SomeRouteClass.new(sinatra, calculator)
routing_class.setup_routes
sinatra.run!
Forgive any spelling/syntax mistakes this is just a quick example, but as you can see a class registers routes and when that route is hit returns some value generated by an instance of the calculator it took when it was instantiated.
Problem I have is that in this example when I try and run the /add route it tells me that @calculator is a nilClass, and I believe it to be down to the way that Sinatra just takes the block of code without context. This seems fine for any simple template rendering, but if you need to do anything more fancy, or want to keep your code modular by not using statics and singletons you do not seem to have any way around this...
Are my assumptions correct here? and if so is there any way to keep context as it feels like it is forcing me to write bad and hard to maintain code if I have to write everything as statics and singletons to interact from a route.
== Edit ==
Have restructured the question and content to more accurately reflect the actual problem, now that I have a firmer understanding of the library.
回答1:
I may not accept this answer, but after doing more research it may be that in a dynamic language like Ruby static classes are not such as nightmare from a maintenance point of view.
It seems that most major Ruby libraries work against static instances (or consts) which get setup then used... this does still seem a little odd to me, as in a database provider point of view. It is very easy to just call your database static class and connect to your database and then start querying, however what if you need to connect to 2 separate databases at the same time. You would need to keep swapping servers with the same static class which would be troublesome.
Anyway it seems at the moment like the answer is just make a constant for everything you need to expose to a route, then when you are testing just set that const to a mock. It still seems a bit crazy calling these things consts, when really they are not consts in the true sense of the word as they can be changed at any time... like many things to new ruby developers it just seems confusing for the sake of it (i.e elsif, @@blah, variable case defining if its const or not).
As I said I will not accept this answer if someone else can show me a better pattern of doing this, but for the moment will give it a few more days.
回答2:
The block passed to get
is evaluated in a different context than the Calculator
object. Sinatra is probably calling instance_eval
or one of its cousins. However, it should be possible to capture local variables from the surrounding scope, using something like the following (untested, alas) approach:
def setup_routes
calculator = @calculator
@sinatra.get "/add" do
return calculator.add(1,1)
end
end
回答3:
class SomeRouteClass
def initialize(sinatra, calculator)
@calculator = calculator
@sinatra = sinatra
end
def calculator
@calculator
end
def setup_routes
@sinatra.get "/add" do
return calculator.add(1,1)
end
end
end
来源:https://stackoverflow.com/questions/8225844/working-around-the-lack-of-context-in-sinatras-route-methods