初步評論:發表所有代碼並且只有最小代碼,以便我們可以複製粘貼並執行它來重現錯誤。在這種情況下,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
塊內的文件,該塊在退出塊時關閉。恢復當前目錄的工作也是一樣的。從The 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
我認爲這意味着,給定的路徑」 ./spec/fixtures/mp3s/some_path。 MP3「它只會給你」some_path.mp3「。順便說一句,我們有[File.basename](https://ruby-doc.org/core-1.9.3/File.html#method-c-basename)。 –
好的。但是,如果是這種情況,那麼在#initialize中設置的路徑不包含文件名。它只是一個路徑,直到mp3目錄「./spec/fixtures/mp3s」..其中作爲'File.basename'將工作,如果文件的完整路徑給出。 –
你可以嘗試使方法返回'Dir.glob(「#{@ path}/*。mp3」)'。除此之外,我不知道。 –