翻译来自 Sinatra: Up and Running
这一段暂时超出我的翻译能力,为了完整性先把英文版的给大家看。(需要翻译的同学请尽量留言让我知道是否有必要)
#Dispatching
There is, however, one catch: Sinatra relies on the “one instance per request” principle. However, when running as middleware, all requests will use the same instance over and over again. Sinatra performs a clever trick here: instead of executing the logic right away, it duplicates the current instance and hands responsibility on to the duplicate instead. Since instance creation (especially with all the middleware being set up internally) is not free from a performance and resources standpoint, it uses that trick for all requests (even if running as endpoint) by keeping a prototype object around.
Example 3-16 shows the secret sauce in Sinatra’s dispatch activities.
Example 3-16. The Sinatra dispatch in action
###Dispatching Redux
This lets us craft some pretty interesting Sinatra applications. This prototype and instance duplication approach means you can safely use call on the current instance and consume the result of another route. If you remember from the earlier discussion on Rack’s methodology, the call method will return an array. The application in Example 3-17 lets you check the status code and headers of other routes. Figure 3-5 shows the output of the inspector application.
Example 3-17. A reflective route inspector
Now let’s tie everything together with the code in Example 3-18 and create a Sinatra application that acts as middleware.
Example 3-18. Using Sinatra as middleware in a fictional Rails project
Figure 3-5. Firing another request internally to inspect the response
###Changing Bindings
To bring the discussion back to where we began, let’s focus on a block passed to get again. How is it that the instance methods are actually available? If you’ve been working with Ruby for a decent length of time, you’ve probably come across instance_eval, which allows you to dynamically change the binding of a block. Example 3-19 demonstrates how this can be used.
Example 3-19. Toying with instance_eval
This is similar to what Sinatra does. In fact, earlier versions of Sinatra do use instance_eval. However, there is an alternative: dynamically create a method from that block, get the unbound method object for that method, and remove the method immediately. When you want to run the code, bind the method object to the current instance and call it.
This has a few advantages over instance_eval: it results in significantly better performance since the scope change only occurs once as opposed to every request. It also allows the passing of arguments to the block. Moreover, since you can name the method yourself, it results in more readable stack traces. All of this logic is wrapped in Sinatra’s generate_method, which you can examine in Figure 3-6 and Example 3-20.
Caution
generate_method is used internally by Sinatra and is not part of the public API. You should not use it directly in your application.
Figure 3-6. generate_method and its usage in Sinatra
Example 3-20. generate_method from sinatra/base.rb