如何将文件名归一化为没有路径的MP3文件名?红宝石



我正在尝试解决一个实验室,但我不确定发生了什么。我要做的是,我必须从目录导入一些文件名(.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. 为什么错误指向目录?目录有所需的文件何时?

初步备注:仅发布所有代码和最小代码,以便我们可以复制和执行它以重现错误。在这种情况下,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

最新更新