我正在尝试解决一个实验室,但我不确定发生了什么。我要做的是,我必须从目录导入一些文件名(.mp3),然后使用文件名来制作一些对象。我仍然坚持从目录中获取文件名。测试要求我
"将文件名归一化为没有路径的MP3文件名"
测试如下:
it 'normalizes the filename to just the mp3 filename with no path' do
test_music_path = "./spec/fixtures/mp3s"
music_importer = MP3Importer.new(test_music_path)
expect(music_importer.files).to include("Action Bronson - Larry Csonka - indie.mp3")
expect(music_importer.files).to include("Real Estate - Green Aisles - country.mp3")
expect(music_importer.files).to include("Real Estate - It's Real - hip-hop.mp3")
expect(music_importer.files).to include("Thundercat - For Love I Come - dance.mp3")
end
我的代码是:
class MP3Importer
attr_accessor :path
def initialize(path)
@path = path
end
def files
Dir.chdir(@path)
filename = Dir.glob("*.mp3")
filename
end
end
这也通过了这两个测试:
describe '#initialize' do
it 'accepts a file path to parse mp3 files from' do
test_music_path = "./spec/fixtures/mp3s"
music_importer = MP3Importer.new(test_music_path)
expect(music_importer.path).to eq(test_music_path)
end
describe '#files' do
it 'loads all the mp3 files in the path directory' do
test_music_path = "./spec/fixtures/mp3s"
music_importer = MP3Importer.new(test_music_path)
expect(music_importer.files.size).to eq(4)
end
但是它所产生的错误是:
Failure/Error: expect(music_importer.files).to include("Action Brons
Errno::ENOENT:
No such file or directory @ dir_chdir - ./spec/fixtures/mp3s
说实话,我不知道没有路径的文件名将文件名正常于MP3文件名?这是非常误导的。我已经在#files方法中的可变文件名上有一系列文件名。
我的问题是:
- 该语句"将文件名正常于没有路径的mp3文件名归一化"?测试要我做什么?
- 发布的代码中发生了什么?
- 为什么错误指向目录?目录有所需的文件何时?
初步备注:仅发布所有代码和最小代码,以便我们可以复制和执行它以重现错误。在这种情况下,RSPEC标签和RSPEC版本也将很有用。
当我执行您的代码时:
No such file or directory @ dir_chdir - ./spec/fixtures/mp3s
# ./lib/t_a.rb:14:in `chdir'
错误在第14行的语句中:
Dir.chdir(@path)
这给出了一个线索,即chdir
在当前工作目录中找不到请求的子目录。为什么 ?添加跟踪以显示当前工作目录:
def files
puts "in files, path=#{@path}"
puts "wd=...#{Dir.getwd.sub(/.*ruby(.*)/, '1')}"
current_dir = Dir.getwd
Dir.chdir(@path)
...
并运行测试(我在...devl/ruby/zintlist/mp3_importer
中工作):
$ rspec
MP3Importer
#initialize
accepts a file path to parse mp3 files from
#files
in files, path=./spec/fixtures/mp3s
wd=.../zintlist/mp3_importer
loads all the mp3 files in the path directory
#xxxx
in files, path=./spec/fixtures/mp3s
wd=.../zintlist/mp3_importer/spec/fixtures/mp3s
,您会看到区别:
wd=.../zintlist/mp3_importer
wd=.../zintlist/mp3_importer/spec/fixtures/mp3s
执行files
时,您会产生副作用:当前目录已更改。在files
的第二次执行中,Dir.chdir
开始在第一个执行剩下的当前目录中搜索.../mp3_importer/spec/fixtures/mp3s
,并且mp3s
当然不包含./spec/fixtures/mp3s
,因此错误No such file or directory
。
解决方案是还原输入方法时的当前目录:
def files
puts "in files, path=#{@path}"
puts "wd=...#{Dir.getwd.sub(/.*ruby(.*)/, '1')}"
current_dir = Dir.getwd
Dir.chdir(@path)
filenames = Dir.glob("*.mp3")
Dir.chdir(current_dir)
filenames
end
然后,痕迹显示了它已恢复:
wd=.../zintlist/mp3_importer
...
wd=.../zintlist/mp3_importer
您可能已经知道,如果您在File.open ... do ... end
块内处理文件,则在块退出时关闭文件。同样的工作来还原当前目录。从pickaxe dir.chdir:
如果给出了一个块,则将其传递给新电流的名称 目录,并用当前执行该块 目录。当块时,原始工作目录将恢复 退出。
给定以下文件:
#file t.rb
class MP3Importer
attr_accessor :path
def initialize(path)
@path = path
end
def files
# puts "in files, path=#{@path}"
# puts "wd=#{Dir.getwd.sub(/.*ruby(.*)/, '1')}"
filenames = Dir.chdir(@path) do | path |
# puts path
Dir.glob("*.mp3")
end
puts "names=#{filenames}"
filenames
end
end
。
# file t_spec.rb
require 't'
RSpec.describe MP3Importer do
let(:test_music_path) { "./spec/fixtures/mp3s" }
let(:music_importer) { MP3Importer.new(test_music_path) }
describe '#initialize' do
it 'accepts a file path to parse mp3 files from' do
expect(music_importer.path).to eq(test_music_path)
end
end
describe '#files' do
it 'loads all the mp3 files in the path directory' do
expect(music_importer.files.size).to eq(4)
end
end
describe '#xxxx' do
it 'normalizes the filename to just the mp3 filename with no path' do
expect(music_importer.files).to include('f4.mp3')
end
end
end
执行:
$ ruby -v
ruby 2.4.0rc1 (2016-12-12 trunk 57064) [x86_64-darwin15]
$ rspec -v
RSpec 3.6.0.beta2
- rspec-core 3.6.0.beta2
- rspec-expectations 3.6.0.beta2
- rspec-mocks 3.6.0.beta2
- rspec-support 3.6.0.beta2
$ rspec
MP3Importer
#initialize
accepts a file path to parse mp3 files from
#files
names=["f1.mp3", "f2.mp3", "f3.mp3", "f4.mp3"]
loads all the mp3 files in the path directory
#xxxx
names=["f1.mp3", "f2.mp3", "f3.mp3", "f4.mp3"]
normalizes the filename to just the mp3 filename with no path
Finished in 0.00315 seconds (files took 0.09868 seconds to load)
3 examples, 0 failures
所有测试都是绿色的。
由于方法返回值是最后执行的表达式的值,因此您可以像这样简化files
:
def files
Dir.chdir(@path) do | path |
Dir.glob("*.mp3")
end
end
该语句"归一化...含义?
我不知道。我想它仅收集名称对应于某个模式的文件,此处 *.mp3
。
我可以说的是,RDOC从命令行中获取输入文件名,并将其传递给一个名为normalized_file_list
的例程:
# file rdoc.rb
##
# Given a list of files and directories, create a list of all the Ruby
# files they contain.
#
# If +force_doc+ is true we always add the given files, if false, only
# add files that we guarantee we can parse. It is true when looking at
# files given on the command line, false when recursing through
# subdirectories.
#
# The effect of this is that if you want a file with a non-standard
# extension parsed, you must name it explicitly.
def normalized_file_list(relative_files, force_doc = false,
exclude_pattern = nil)
file_list = []
relative_files.each do |rel_file_name|
next if rel_file_name.end_with? 'created.rid'
next if exclude_pattern && exclude_pattern =~ rel_file_name
stat = File.stat rel_file_name rescue next
case type = stat.ftype
when "file" then
next if last_modified = @last_modified[rel_file_name] and
stat.mtime.to_i <= last_modified.to_i
if force_doc or RDoc::Parser.can_parse(rel_file_name) then
file_list << rel_file_name.sub(/^.//, '')
@last_modified[rel_file_name] = stat.mtime
end
when "directory" then
next if rel_file_name == "CVS" || rel_file_name == ".svn"
created_rid = File.join rel_file_name, "created.rid"
next if File.file? created_rid
dot_doc = File.join rel_file_name, RDoc::DOT_DOC_FILENAME
if File.file? dot_doc then
file_list << parse_dot_doc_file(rel_file_name, dot_doc)
else
file_list << list_files_in_directory(rel_file_name)
end
else
warn "rdoc can't parse the #{type} #{rel_file_name}"
end
end
file_list.flatten
end
##
# Return a list of the files to be processed in a directory. We know that
# this directory doesn't have a .document file, so we're looking for real
# files. However we may well contain subdirectories which must be tested
# for .document files.
def list_files_in_directory dir
files = Dir.glob File.join(dir, "*")
normalized_file_list files, false, @options.exclude
end