当我运行bundle exec rspec时,出现此错误“ rspec未定义方法`title =”。请注意,在规格文件中,其名为“ title”而不是“ title =“的ive搜索了整个规格文件,以查看是否可以找到一个错字,但没有运气。 这是它给我的错误:
Book
title
should capitalize the first letter (FAILED - 1)
Failures:
1) Book title should capitalize the first letter
Failure/Error: @book.title = "inferno"
NoMethodError:
undefined method `title=' for #<Book:0x007fec2b140450>
这是规格文件中停在以下位置的部分:
require '08_book_titles'
describe Book do
before do
@book = Book.new
end
describe "title" do
it "should capitalize the first letter" do
@book.title = "inferno"
expect(@book.title).to eq("Inferno")
end
据我所知,尝试之后,它混淆了“ @ book.title =” inferno“”中的标题为“ title =”(我将标题更改为另一个单词,并将该单词与等于结尾处)。我不确定为什么它在方法的末尾添加了一个相等的数字。
(我注释掉了所有我自己的代码,以确保错误来自规范文件)
答案 0 :(得分:4)
tl; dr :
在"should capitalize the first letter"
示例中,您设置了书名,但该类未实现该方法。
NoMethodError: undefined method `title=' for #<Book:0x007fec2b140450>
不言自明,但也可能造成混淆。任何NoMethodError
表示尚未定义要在接收方上尝试访问的方法。
在一个很小的类Car中,用一个实例方法返回车轮总数:
class Car
def initialize
@wheels = '4 big wheels'
end
def wheels
@wheels
end
end
yaris = Car.new
p yaris.wheels # "4 big wheels"
p yaris.doors # `<main>': undefined method `doors' for #<Car:0x0000558d18cfbd68 (NoMethodError)
访问wheels方法将返回预期的结果,但是尝试访问doors方法将引发NoMethodError。 Car类中没有定义方法门。
该示例中的两个方法都称为“ getter”方法,它们返回您在类实现上某些时候可能需要的值。但是,由于有“ getter”方法,也有“ setter”方法,它们使用=
符号定义。
在示例类中,我们在initialize方法中定义@wheels实例变量,然后通过wheels方法访问它们。但是如果您想重新定义车轮呢?也许是您撞坏了汽车,现在它只有3个车轮,所以,您需要一种方法来设置@wheels的值。
让我们尝试设置它们:
yaris = Car.new
p yaris.wheels # "4 big wheels"
yaris.wheels = '3 working wheels' # undefined method `wheels=' for #<Car:0x000055755ad933c8 @wheels="4 big wheels"> (NoMethodError)
现在您不能了,因为没有wheels=
方法,因此不能那样更改@wheels的值。所以,不是,请定义它:
...
def wheels=(value)
@wheels = value
end
end
yaris = Car.new
p yaris.wheels # "4 working wheels"
yaris.wheels = '3 working wheels'
p yaris.wheels # "3 working wheels"
就是这样,您现在就可以从任何Car实例获取并设置车轮。
大多数时候,您不会看到像wheels=
这样的方法。由于Ruby具有让您定义类的属性访问器的能力。您可以使用attr_reader:wheels定义类,这将为您提供@wheels的值:
class Car
attr_reader :wheels
def initialize
@wheels = '4 big wheels'
end
end
yaris = Car.new
p yaris.wheels # "4 working wheels"
它的工作方式相同,但是同样,您无法定义@wheels的值,因为只有一个read属性,如果您愿意,则可以添加attr_reader的兄弟attr_writer:>
class Car
attr_reader :wheels
attr_writer :wheels
def initialize
@wheels = '4 big wheels'
end
end
现在完成了,您可以读取和设置@wheels值,但是为什么还要麻烦地一一写入读写器属性。您可以在作为参数传递的特定属性上使用attr_accessor,它在您的类上同时实现wheels
和wheels=
方法。
class Car
attr_accessor :wheels
...
end
p Car.instance_methods(false) # [:wheels=, :wheels]
为什么这么无聊?因为如果您能够知道这些方法的来源,那么您将能够知道它们为什么会出现或为什么不在应该出现的地方。不管使用什么框架,DSL,无论您使用什么其他框架,都是Ruby。