lib/alf/reader/class_methods.rb in alf-0.10.1 vs lib/alf/reader/class_methods.rb in alf-0.11.0
- old
+ new
@@ -1,82 +1,91 @@
module Alf
class Reader
module ClassMethods
-
- #
- # Returns registered readers
- #
+
+ # @return [Array<Reader>] registered readers
def readers
@readers ||= []
end
-
- #
- # Registers a reader class associated with specific file extensions
+
+ # Registers a reader class associated with specific file extensions.
#
# Registered class must provide a constructor with the following signature
- # <code>new(path_or_io, environment = nil)</code>. 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.
+ # `new(path_or_io, environment = nil, options = {})`. The registration
+ # name must be a symbol which can safely be used as a ruby method name.
+ # A factory method of that name and 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
- #
+ # @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 looks like a String or a path, returns a reader instance
+ # for the source it denotes. Otherwise, delegates the call to
+ # `coerce(filepath)`.
#
- # When filepath is a String, returns a reader instance for a specific file
- # whose path is given as argument. Otherwise, delegate the call to
- # <code>coerce(filepath)</code>
- #
- # @param [String] filepath path to a file for which extension is recognized
+ # @param [:to_str|:to_path] 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
- #
+ # @return [Reader] a reader instance built from arguments
+ # @raise [ArgumentError] if `filepath` is not recognized or no reader can
+ # be found for this extension.
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?
+ if looks_a_path?(filepath)
+ ext = File.extname(filepath.to_s)
+ has_reader_for_ext!(ext).new(filepath.to_s, *args)
+ elsif args.empty?
coerce(filepath)
else
raise ArgumentError, "Unable to return a reader for #{filepath} and #{args}"
end
end
-
+
+ # Coerces `arg` to a Reader instance, using an optional environment to
+ # convert named datasets.
#
- # Coerces an argument to a reader, using an optional environment to convert
- # named datasets.
+ # This method automatically provides readers for Strings and Symbols
+ # through `environment` (**not** through the reader factory) and for IO
+ # objects through a Rash reader.
#
- # 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.
- #
+ # @param [Object] arg any value to coerce to a Reader instance
+ # @param [Environment] environment to resolved named datasets (optional)
def coerce(arg, environment = nil)
case arg
when Reader
arg
when IO, StringIO
rash(arg, environment)
else
raise ArgumentError, "Unable to coerce #{arg.inspect} to a reader"
end
end
-
+
+ private
+
+ # Checks if `path` looks like a usable path
+ def looks_a_path?(path)
+ return false if path.is_a?(StringIO)
+ path.respond_to?(:to_str) or path.respond_to?(:to_path)
+ end
+
+ # @return [Class] the reader class to use for `ext` file extension.
+ # @raise [ArgumentError] if no such reader class can be found
+ def has_reader_for_ext!(ext)
+ entry = readers.find{|r| r[1].include?(ext)}
+ return entry[2] if entry
+ raise ArgumentError, "No registered reader for #{ext}"
+ end
+
end # module ClassMethods
extend(ClassMethods)
end # class Reader
end # module Alf