Ruby:通过使用模块扩展File来处理文件格式

一旦我有一个File实例,我想检查它是否与文件格式匹配,并使用相应的方法extend该实例:

 module MP3 def self.extended(base) raise "Can only extend a File" unless base.is_a?(File) raise "Incorrect file format" unless is_mp3?(base) end def self.is_mp3?(file) # Full metadata check if it is a MP3 format end def year # Extract year from metadata end end song = File.new("song.mp3") if MP3.is_mp3?(song) song.extend(MP3) puts song.ctime # Original File method puts song.year # Extended MP3 method end picture = File.new("picture.jpg") MP3.is_mp3?(picture) #=> False picture.extend(MP3) #=> raise "Incorrect file format" 

我想这不是传统的,但我的需求是:

  • 能够处理多种文件格式。
  • 在知道其格式之前打开文件。
  • 无需创建新对象即可重用相同的File实例。 (见下文)
  • 在同一对象中同时具有原始File方法和格式化特定方法。
  • 在添加相应方法之前检查文件格式是否正确。

这种方法是否正确?

这个问题是前一个问题的后续问题 。

我想扩展现有的File实例,而不是创建一个新实例,因为我正在使用File的包装器,它将整个文件保存在RAM中(从不允许顺序访问的磁带驱动器读取)。

你提出的建议太过于选择在调用者代码中使用哪个类的逻辑。 每次添加新文件类型时,都需要更改代码的使用位置。

而是使用Factory模式 。 写一个类(工厂)来检查文件名并决定做什么。 除了我将使用更优越的路径名 。

 require "pathname" class Pathname::Format def self.from_filename(filename) path = Pathname.new(filename) from_pathname!(path) return path end def self.from_pathname!(path) case path.extname when ".mp3" path.extend(MP3) when ".jpg" path.extend(JPG) end return end end 

要点是将决定放入工厂类,而不是调用代码。

然后你可以编写你的模块。

 module JPG def type return "JPG" end end module MP3 def type return "MP3" end def year puts "MP3 year called" end end 

现在呼叫者只使用工厂。

 # From a filename song = Pathname::Format.from_filename("song.mp3") puts song.ctime # Original File method puts song.year # Extended MP3 method # From a Pathname picture = Pathname.new("picture.jpg") Pathname::Format.from_pathname!(picture) puts picture.type 

而不是增加特殊方法来检查对象是否属于特定类型,或者检查type方法,检查它是否是一种模块,或者依赖于鸭子类型 。

 if song.type == "MP3" puts song.year end if song.kind_of?(MP3) puts song.year end if song.respond_to?("year") puts song.year end