Sinatra :: Base.condition实际上做了什么?

LJ.*_*LJ. 6 ruby session block sinatra

我遇到了sinatra 条件方法,并对它是如何工作感到困惑.

我有一段代码:

def auth user
  condition do
    redirect '/login' unless user_logged_in?
  end
end
Run Code Online (Sandbox Code Playgroud)

其中检查用户是否记录了某些路由,示例路由:

get '/', :auth => :user do
  erb :index
end
Run Code Online (Sandbox Code Playgroud)

该方法user_logged_in?在项目的lib目录中的辅助文件中定义:

def user_logged_in?
  if session[:user]
    @user = session[:user]
    return @user
  end 
  return nil 
end
Run Code Online (Sandbox Code Playgroud)

所以,问题是:condition块是如何知道session[:user]包含什么的,在get '/'路径session[:user]上甚至没有设置?

condition方法在以下GitHub页面中定义:sinatra基本条件方法 谢谢.

mat*_*att 4

定义路由时,选项哈希的每个成员的键将作为方法调用,值作为参数传递

因此,当您执行此操作时get '/', :auth => :user do ...,该方法auth将使用参数调用:user。这又调用condition该块的方法。

condition方法实际上是在您链接到它的用法上方定义的。它看起来像这样:

def condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @conditions << generate_method(name, &block)
end
Run Code Online (Sandbox Code Playgroud)

generate_method方法将块转换为具有给定名称的方法,然后将该方法保存在数组中@conditions。然后,内容@conditions与路线定义一起保存,并被@conditions清除,为下一个路线定义做好准备。

此时,传递给的代码块condition尚未执行。它实际上已被保存以供以后使用。

当实际请求到来时,如果请求路径与路由匹配,则执行与该路由关联的每个条件以检查它是否满足。在此示例中,这是redirect '/login' unless user_logged_in?首次执行的时间,因此遗嘱session已设置并且session[:user]可用(如果未登录则不可用)。

理解这一点的重要一点是,当您将块传递给方法时,不一定会立即调用该块中的代码。在这种情况下,仅当实际请求到达时才会调用块中的代码。