2017-10-04 130 views
0

我想解決一個實驗,但我不知道發生了什麼事情。我必須做的是,我必須從目錄中導入一些文件名(.mp3's),然後使用文件名製作一些對象。我仍然堅持從目錄中獲取文件名。測試要求我如何規範文件名只是沒有路徑的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方法中已經有了可變文件名的文件名數組。

我的問題是:

  1. 這句話是什麼「規範化文件名,只是不帶路徑的文件名的MP3」是什麼意思?測試要我做什麼?
  2. 發佈代碼時發生了什麼?
  3. 爲什麼錯誤指向目錄?當目錄確實有必要的文件?
+1

我認爲這意味着,給定的路徑」 ./spec/fixtures/mp3s/some_path。 MP3「它只會給你」some_path.mp3「。順便說一句,我們有[File.basename](https://ruby-doc.org/core-1.9.3/File.html#method-c-basename)。 –

+0

好的。但是,如果是這種情況,那麼在#initialize中設置的路徑不包含文件名。它只是一個路徑,直到mp3目錄「./spec/fixtures/mp3s」..其中作爲'File.basename'將工作,如果文件的完整路徑給出。 –

+1

你可以嘗試使方法返回'Dir.glob(「#{@ path}/*。mp3」)'。除此之外,我不知道。 –

回答

1

初步評論:發表所有代碼並且只有最小代碼,以便我們可以複製粘貼並執行它來重現錯誤。在這種情況下,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/mp3smp3s當然不包含./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