Here is a bit of code from M Hartl's Ruby on Rails Tutorial. Can anyone explain why an instance variable (@user) is necessary and why not use a local variable. Also, since instance variables are supposed to be the variables in the instance of a class, which class is @user instantiated from?
这里有一些来自M Hartl的Ruby on Rails教程的代码。谁能解释为什么需要实例变量(@user),为什么不使用局部变量?而且,既然实例变量应该是类实例中的变量,那么@user是从哪个类实例化的呢?
require 'spec_helper'
describe User do
before { @user = User.new(name: "Example User", email: "user@example.com") }
subject { @user }
it { should respond_to(:name) }
it { should respond_to(:email) }
end
3 个解决方案
#1
32
Use of a local variable in that instance would mean that its scope would be restricted to the before
and hence result in an error. The @user
is of type User but is an instance variable of the describe
block. Rspec has some magic that at run-time makes a class out of each describe
block. Each example (it
block) ends up being a subclass of said class. Class inheritance lets the examples see @user
.
在该实例中使用局部变量将意味着其范围将被限制在之前,从而导致错误。@user类型为User,但是是description块的实例变量。Rspec有一些神奇之处,即在运行时利用每个description块创建类。每个示例(it块)最后都是类的子类。类继承让示例看到@user。
Edited 2017-05-14
编辑2017-05-14
Linked blog post is no longer available. Updating with Wayback Machine link + inlining relevant section here.
链接的博客文章不再可用。使用回线机链接+在这里插入相关部分进行更新。
Note that this is considered an anti-pattern as detailed in this blog post. Use let
instead.
注意,这被认为是一个反模式,在这篇博文中有详细的介绍。使用我们。
let
has the following advantages:
让我们拥有以下优势:
- It is memoized when used multiple times in one example, but not across examples.
- 当在一个示例中多次使用它时,它是可记忆的,但不能跨示例使用。
- It is lazy-loaded, so you wont waste time initializing the variable for examples that don't reference it.
- 它是延迟加载的,所以您不会浪费时间为不引用变量的示例初始化变量。
- Will raise an exception if you have a typo in your variable name.
- 如果您的变量名中有一个输入错误,将引发异常。
#2
12
You can't use a local variable because a local variable exists only in the scope of the local method. before
, subject
and it
generates different scopes within the same class.
您不能使用局部变量,因为局部变量仅存在于本地方法的范围内。在此之前,subject和它在同一个类中生成不同的范围。
The following code
下面的代码
before { user = User.new(name: "Example User", email: "user@example.com") }
will raise an undefined variable when you call it in
当你调用一个未定义的变量时
subject { user }
The instance @user
is an instance of the class User
(after all, you create it with User.new
).
实例@user是类User的一个实例(毕竟,您使用User.new创建它)。
However, instead of instance variables you might want to use the let
command. Also, if you define
但是,您可能希望使用let命令而不是实例变量。另外,如果您定义
subject { User.new(name: "Example User", email: "user@example.com") }
the use of before
is not required. You'll also get the extra benefit to get a subject
method available to access the instance, equal to define let(:subject)
.
使用之前是不需要的。您还将获得额外的好处,使subject方法可以访问实例,等于定义let(:subject)。
#3
2
subject
ad it
blocks are under different scopes, so local variables won't work. @user
belongs to class generated by RSpec under the hood.
主题广告在不同的范围内,所以局部变量不起作用。@user属于RSpec在hood下生成的类。
#1
32
Use of a local variable in that instance would mean that its scope would be restricted to the before
and hence result in an error. The @user
is of type User but is an instance variable of the describe
block. Rspec has some magic that at run-time makes a class out of each describe
block. Each example (it
block) ends up being a subclass of said class. Class inheritance lets the examples see @user
.
在该实例中使用局部变量将意味着其范围将被限制在之前,从而导致错误。@user类型为User,但是是description块的实例变量。Rspec有一些神奇之处,即在运行时利用每个description块创建类。每个示例(it块)最后都是类的子类。类继承让示例看到@user。
Edited 2017-05-14
编辑2017-05-14
Linked blog post is no longer available. Updating with Wayback Machine link + inlining relevant section here.
链接的博客文章不再可用。使用回线机链接+在这里插入相关部分进行更新。
Note that this is considered an anti-pattern as detailed in this blog post. Use let
instead.
注意,这被认为是一个反模式,在这篇博文中有详细的介绍。使用我们。
let
has the following advantages:
让我们拥有以下优势:
- It is memoized when used multiple times in one example, but not across examples.
- 当在一个示例中多次使用它时,它是可记忆的,但不能跨示例使用。
- It is lazy-loaded, so you wont waste time initializing the variable for examples that don't reference it.
- 它是延迟加载的,所以您不会浪费时间为不引用变量的示例初始化变量。
- Will raise an exception if you have a typo in your variable name.
- 如果您的变量名中有一个输入错误,将引发异常。
#2
12
You can't use a local variable because a local variable exists only in the scope of the local method. before
, subject
and it
generates different scopes within the same class.
您不能使用局部变量,因为局部变量仅存在于本地方法的范围内。在此之前,subject和它在同一个类中生成不同的范围。
The following code
下面的代码
before { user = User.new(name: "Example User", email: "user@example.com") }
will raise an undefined variable when you call it in
当你调用一个未定义的变量时
subject { user }
The instance @user
is an instance of the class User
(after all, you create it with User.new
).
实例@user是类User的一个实例(毕竟,您使用User.new创建它)。
However, instead of instance variables you might want to use the let
command. Also, if you define
但是,您可能希望使用let命令而不是实例变量。另外,如果您定义
subject { User.new(name: "Example User", email: "user@example.com") }
the use of before
is not required. You'll also get the extra benefit to get a subject
method available to access the instance, equal to define let(:subject)
.
使用之前是不需要的。您还将获得额外的好处,使subject方法可以访问实例,等于定义let(:subject)。
#3
2
subject
ad it
blocks are under different scopes, so local variables won't work. @user
belongs to class generated by RSpec under the hood.
主题广告在不同的范围内,所以局部变量不起作用。@user属于RSpec在hood下生成的类。