如何将文件名规范化为没有路径的 mp3 文件名? Ruby

How to normalise the filename to just the mp3 filename with no path ? Ruby

我正在尝试解决实验室问题,但我不确定发生了什么。我必须做的是,我必须从目录中导入一些文件名(.mp3),然后使用文件名制作一些对象。我仍然坚持从目录中获取文件名。测试要求我

"Normalise the filename to just the mp3 filename with no path"

测试如下:

  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. 语句 "Normalise the filename to just the mp3 filename with no path" 是什么意思?测试要我做什么?
  2. 发布的代码中发生了什么?
  3. 为什么错误指向目录?当目录确实有所需的文件时?

初步说明:post所有代码,只有最少的代码,以便我们可以复制粘贴并执行它来重现错误。 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(.*)/, '')}"
    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当然不包含[=29] =],因此错误 No such file or directory.

解决方法是恢复进入方法时的当前目录:

def files
    puts "in files, path=#{@path}"
    puts "wd=...#{Dir.getwd.sub(/.*ruby(.*)/, '')}"
    current_dir = Dir.getwd
    Dir.chdir(@path)
    filenames = Dir.glob("*.mp3")
    Dir.chdir(current_dir)
    filenames
end

然后trace显示已经恢复:

wd=.../zintlist/mp3_importer
...
wd=.../zintlist/mp3_importer

您可能已经知道,如果您在 File.open ... do ... end 块内处理文件,则该文件会在块退出时关闭。这同样适用于恢复当前目录。来自 The Pickaxe Dir.chdir :

If a block is given, it is passed the name of the new current directory, and the block is executed with that as the current directory. The original working directory is restored when the block exits.

鉴于这些文件:

#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(.*)/, '')}"
        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

所有测试都是绿色的。

因为方法 return 的值是最后执行的表达式的值,你可以像这样简化 files :

def files
    Dir.chdir(@path) do | path |
        Dir.glob("*.mp3")
    end
end

What does the statement "Normalise ... mean ?

我不知道。我想它只收集名称对应于特定模式的文件,这里 *.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