解决 Sinatra 路线方法中缺乏上下文的问题
在调用我的路线时,我一直遇到缺少实例和 nilClass 错误的问题。在深入研究源代码之后,似乎generate_method调用基本上使用初始方法的块创建了一个新方法。
get "/" do
@some_local_instance.do_something()
end
因此,在上面的方法中,该类中很可能有一个名为 some_local_instance 的局部变量,但是当实际评估死记硬背时,它没有关于定义该方法的上下文,因此它将失败。
我问的原因是因为作为我的脚本的一部分,我有外部类,这些外部类在加载 Sinatra 时加载,这些类注册路由,并且当调用这些路由时,我需要访问这些类上的一些局部变量。一个例子是:
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!
请原谅任何拼写/语法错误,这只是一个简单的例子,但是正如您所看到的,一个类注册了路由,并且当该路由被命中时,返回由实例化时所采用的计算器实例生成的一些值。
我遇到的问题是,在这个例子中,当我尝试运行 /add 路由时,它告诉我 @calculator 是一个 nilClass,我相信这取决于 Sinatra 只获取没有上下文的代码块的方式。这对于任何简单的模板渲染来说似乎都很好,但是如果您需要做任何更奇特的事情,或者想要通过不使用静态和单例来保持代码模块化,您似乎没有任何办法解决这个问题......
我的假设在这里是否正确?如果是这样,有什么方法可以保留上下文,因为如果我必须将所有内容都编写为静态和单例才能从路由进行交互,那么这感觉就像迫使我编写糟糕且难以维护的代码。
== 编辑==
现在我对图书馆有了更深入的了解,已经重组了问题和内容,以更准确地反映实际问题。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我可能不接受这个答案,但经过更多研究后,从维护的角度来看,在像 Ruby 这样的动态语言中,静态类可能并不是噩梦。
似乎大多数主要的 Ruby 库都针对静态实例(或常量)工作,这些实例先设置然后使用......这对我来说仍然有点奇怪,就像从数据库提供者的角度来看一样。只需调用数据库静态类并连接到数据库然后开始查询是非常容易的,但是如果您需要同时连接到 2 个单独的数据库怎么办?您需要不断地交换具有相同静态类的服务器,这会很麻烦。
无论如何,目前看来答案只是为您需要公开给路由的所有内容创建一个常量,然后在测试时只需将该常量设置为模拟即可。将这些东西称为 const 似乎仍然有点疯狂,但实际上它们并不是真正意义上的 const,因为它们可以随时更改......就像许多新的 Ruby 开发人员一样,这似乎令人困惑它(即 elsif、@@blah、定义其是否为 const 的变量大小写)。
正如我所说,如果其他人可以向我展示更好的模式,我不会接受这个答案,但目前会再给它几天时间。
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.
传递给
get
的块在与Calculator
对象不同的上下文中进行计算。 Sinatra 可能正在调用instance_eval
或其同类之一。但是,应该可以使用类似以下(未经测试,唉)的方法从周围范围捕获局部变量:The block passed to
get
is evaluated in a different context than theCalculator
object. Sinatra is probably callinginstance_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: