module Alf class Reader module ClassMethods # # Returns registered readers # def readers @readers ||= [] end # # Registers a reader class associated with specific file extensions # # Registered class must provide a constructor with the following signature # new(path_or_io, environment = nil). The name must be a symbol # which can safely be used as a ruby method name. A factory class method of # that name and same signature is automatically installed on the Reader # class. # # @param [Symbol] name a name for the kind of data decoded # @param [Array] extensions file extensions mapped to the registered reader # class (should include the '.', e.g. '.foo') # @param [Class] class Reader subclass used to decode this kind of files # def register(name, extensions, clazz) readers << [name, extensions, clazz] (class << self; self; end). send(:define_method, name) do |*args| clazz.new(*args) end end # # When filepath is a String, returns a reader instance for a specific file # whose path is given as argument. Otherwise, delegate the call to # coerce(filepath) # # @param [String] filepath path to a file for which extension is recognized # @param [Array] args optional additional arguments that must be passed at # reader's class new method. # @return [Reader] a reader instance # def reader(filepath, *args) if filepath.is_a?(String) ext = File.extname(filepath) if registered = readers.find{|r| r[1].include?(ext)} registered[2].new(filepath, *args) else raise "No registered reader for #{ext} (#{filepath})" end elsif args.empty? coerce(filepath) else raise ArgumentError, "Unable to return a reader for #{filepath} and #{args}" end end # # Coerces an argument to a reader, using an optional environment to convert # named datasets. # # This method automatically provides readers for Strings and Symbols through # passed environment (**not** through the reader factory) and for IO objects # (through Rash reader). It is part if Alf's internals and should be used # with care. # def coerce(arg, environment = nil) case arg when Reader arg when IO rash(arg, environment) else raise ArgumentError, "Unable to coerce #{arg.inspect} to a reader" end end end # module ClassMethods extend(ClassMethods) end # class Reader end # module Alf