返回获取有关Bloc课程作业的更多帮助。决定带给你们一些我正在使用Monkey Patching the Array Class的问题。这个作业要达到 8 specs ,而我现在只剩一个了,我不知道该怎么做。
我只会向你提供RSpec和书面要求,因为我遇到了其他一切似乎正在传递的问题。我还要包括他们给我开始的起始脚手架,这样就没有混淆或无用的代码添加。
以下是Array Class Monkey Patch的书面要求:
编写一个在new_map
类的实例上调用的新Array
方法。它应该使用它作为隐式(self
)参数调用的数组,但在其他方面表现相同。 (的 INCOMPLETE )
写一个new_select!行为类似于select的方法,但会改变它所调用的数组。它可以使用Ruby的内置集合选择方法。 (的 COMPLETE )
以下是有关Array类需要满足的RSpec:
注意:"返回一个包含更新值的数组"是唯一没有通过的规格。
describe Array do
describe '#new_map' do
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
it "does not call #map" do
array = [1,2,3,4]
array.stub(:map) { '' }
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
end
it "does not change the original array" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array ).to eq([1,2,3,4])
end
end
describe '#new_select!' do
it "selects according to the block instructions" do
expect( [1,2,3,4].new_select!{ |e| e > 2 } ).to eq( [3,4] )
expect( [1,2,3,4].new_select!{ |e| e < 2 } ).to eq( [1] )
end
it "mutates the original collection" do
array = [1,2,3,4]
array.new_select!(&:even?)
expect(array).to eq([2,4])
end
end
end
这是他们开始使用的脚手架:
class Array
def new_map
end
def new_select!(&block)
end
end
最后,这是我的代码:
class Array
def new_map
new_array = []
self.each do |num|
new_array << num.to_s
end
new_array
end
def new_select!(&block)
self.select!(&block)
end
end
答案 0 :(得分:3)
查看此处的规范:
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
看起来他们只是想让你重新编写Array.map
,以便它可以与任何给定的块一起使用。在您的实现中,您告诉方法以非常特定的方式工作,即在所有数组元素上调用.to_s
。但是你不希望它总是字符串化数组元素。在调用方法时,您希望它对每个元素执行任何块提供。试试这个:
class Array
def new_map
new_array = []
each do |num|
new_array << yield(num)
end
new_array
end
end
请注意,在我的示例中,方法定义未指定要对self
的每个元素执行的任何特定操作。它只是循环遍历数组的每个元素,产生元素(num
)到调用.new_map
时传递的任何块,并将结果铲入new_array
变量。
通过.new_map
和array = [1,2,3,4]
的实现,您可以调用array.new_map(&:to_s)
(块是对每个元素执行的任意操作的位置指定了数组)并获取["1","2","3","4"]
,或者您可以致电array.new_map { |e| e + 2 }
并获取[3,4,5,6]
。
答案 1 :(得分:1)
我想谈谈new_select!
。
选择vs选择!
你有:
class Array
def new_select!(&block)
self.select!(&block)
end
end
你可以写一下:
class Array
def new_select!
self.select! { |e| yield(e) }
end
end
这使用方法Array#select!。您说Array#select可以使用,但没有提到select!
。如果您无法使用select!
,则必须执行以下操作:
class Array
def new_select!(&block)
replace(select(&block))
end
end
我们试一试:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
显式vs隐式接收器
请注意,我没有为方法Array#replace和Array#select
提供任何明确的接收器。当没有明确的接收者时,Ruby假定它是self
,即a
。因此,Ruby评估replace(select(&block))
,好像它是用显式接收器编写的:
self.replace(self.select(&block))
由您决定是否要包含self.
。有些Rubiests有,有些则没有。您会注意到在Ruby中实现的Ruby内置方法中不包含self.
。另一件事:在某些情况下需要self.
以避免歧义。例如,如果taco=
是实例变量@taco
的setter,则必须编写self.taco = 7
来告诉Ruby您指的是setter方法。如果您编写taco = 7
,Ruby将假设您要创建局部变量taco
并将其值设置为7.
两种形式的选择!
您的方法new_select!
是select!
的直接替代品吗?也就是说,两种方法在功能上是否相同?如果您查看Array#select!
的文档,您会看到它有两种形式,一种是您模仿的形式,另一种是您尚未实现的形式。
如果没有给select!
一个块,它将返回一个枚举器。现在你为什么要这样做?假设你想写:
a = [1,2,3,4,5]
a.select!.with_index { |n,i| i < 2 }
#=> [1, 2]
select!
被封锁了吗?不,所以它必须返回一个枚举器,它成为方法Enumerator#with_index的接收者。
我们试一试:
enum0 = a.select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:select!>
现在:
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3, 4, 5]:select!>:with_index>
您可以将enum1
视为“复合枚举器”。在定义enum1
时,请仔细查看Ruby返回的对象的描述(上图)。
我们可以通过将枚举器转换为数组来查看枚举器的元素:
enum1.to_a
# => [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]
这五个元素中的每一个都被传递到块并通过Enumerator#each(调用Array#each)分配给块变量。
足够了,但关键是当没有给出块时让方法返回枚举器是允许我们链接方法的原因。
当没有给出阻止时,你没有一个确保new_select!
返回枚举数的测试,所以也许这不是预期的,但为什么不给它一个去?
class Array
def new_select!(&block)
if block_given?
replace(select(&block))
else
to_enum(:new_select!)
end
end
end
试一试:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.each { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.with_index.each { |n,i| i>2 }
#=> [4, 5]
a #=> [4, 5]