Class: Importer::DataReader
- Inherits:
-
Object
- Object
- Importer::DataReader
- Defined in:
- lib/iron/import/data_reader.rb
Overview
Base class for our input reading - dealing with the raw file/stream, and extracting raw values. In addition, we provide the base data coercion/parsing for our derived classes.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#format ⇒ Object
readonly
Attributes.
Class Method Summary collapse
- .for_format(importer, format) ⇒ Object
- .for_path(importer, path) ⇒ Object
- .for_stream(importer, stream) ⇒ Object
-
.path_from_stream(stream) ⇒ Object
Try to find the original file name for the given stream, as in the case where a file is uploaded to Rails and we’re dealing with an ActionDispatch::Http::UploadedFile.
- .verify_roo! ⇒ Object
Instance Method Summary collapse
-
#initialize(importer, format) ⇒ DataReader
constructor
A new instance of DataReader.
- #load(path_or_stream) ⇒ Object
-
#parse_value(val, type) ⇒ Object
Provides default value parsing/coersion for all derived data readers.
Constructor Details
#initialize(importer, format) ⇒ DataReader
Returns a new instance of DataReader.
60 61 62 63 64 |
# File 'lib/iron/import/data_reader.rb', line 60 def initialize(importer, format) @importer = importer @format = format @multisheet = true end |
Instance Attribute Details
#format ⇒ Object (readonly)
Attributes
9 10 11 |
# File 'lib/iron/import/data_reader.rb', line 9 def format @format end |
Class Method Details
.for_format(importer, format) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/iron/import/data_reader.rb', line 17 def self.for_format(importer, format) case format when :csv CsvReader.new(importer) when :xls verify_roo! XlsReader.new(importer) when :xlsx verify_roo! XlsxReader.new(importer) else nil end end |
.for_path(importer, path) ⇒ Object
32 33 34 35 36 37 38 39 40 |
# File 'lib/iron/import/data_reader.rb', line 32 def self.for_path(importer, path) format = path.to_s.extract(/\.(csv|xlsx?)\z/i) if format format = format.downcase.to_sym for_format(importer, format) else nil end end |
.for_stream(importer, stream) ⇒ Object
42 43 44 45 |
# File 'lib/iron/import/data_reader.rb', line 42 def self.for_stream(importer, stream) path = path_from_stream(stream) for_path(importer, path) end |
.path_from_stream(stream) ⇒ Object
Try to find the original file name for the given stream, as in the case where a file is uploaded to Rails and we’re dealing with an ActionDispatch::Http::UploadedFile.
50 51 52 53 54 55 56 57 58 |
# File 'lib/iron/import/data_reader.rb', line 50 def self.path_from_stream(stream) if stream.respond_to?(:original_filename) stream.original_filename elsif stream.respond_to?(:path) stream.path else nil end end |
.verify_roo! ⇒ Object
11 12 13 14 15 |
# File 'lib/iron/import/data_reader.rb', line 11 def self.verify_roo! if Gem::Specification.find_all_by_name('roo', '~> 1.13.0').empty? raise "You are attempting to use the iron-import gem to import an Excel file. Doing so requires installing the roo gem, version 1.13.0 or later." end end |
Instance Method Details
#load(path_or_stream) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/iron/import/data_reader.rb', line 66 def load(path_or_stream) # Figure out what we've been passed, and handle it if path_or_stream.respond_to?(:read) # We have a stream (open file, upload, whatever) if respond_to?(:load_stream) # Stream loader defined, run it load_stream(path_or_stream) else # Write to temp file, as some of our readers only read physical files, annoyingly file = Tempfile.new(['importer', ".#{format}"]) file.binmode begin file.write path_or_stream.read file.close load_file(file.path) ensure file.close file.unlink end end elsif path_or_stream.is_a?(String) # Assume it's a path if respond_to?(:load_file) # We're all set, load up the given path load_file(path_or_stream) else # No file handler, so open the file and run the stream processor file = File.open(path_or_stream, 'rb') load_stream(file) end else raise "Unable to load data: #{path_or_stream.inspect}" end # Return our status !@importer.has_errors? end |
#parse_value(val, type) ⇒ Object
Provides default value parsing/coersion for all derived data readers. Attempts to be clever and handle edge cases like converting ‘5.00’ to 5 when in integer mode, etc. If you find your inputs aren’t being parsed correctly, add a custom #parse block on your Column definition.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/iron/import/data_reader.rb', line 109 def parse_value(val, type) return nil if val.nil? || val.to_s == '' case type when :string then val = val.to_s.strip val.blank? ? nil : val when :integer, :int then if val.class < Numeric # If numeric, verify that there's no decimal places to worry about if (val.to_f % 1.0 == 0.0) val.to_i else nil end else # Convert to string, strip off trailing decimal zeros val = val.to_s.strip.gsub(/\.0*$/, '') if val.integer? val.to_i else nil end end when :float then if val.class < Numeric val.to_f else # Convert to string, strip off trailing decimal zeros val = val.to_s.strip if val.match(/\A-?[0-9]+(?:\.[0-9]+)?\z/) val.to_f else nil end end when :cents then if val.is_a?(String) val = val.gsub(/\s*\$\s*/, '') end intval = parse_value(val, :integer) if !val.is_a?(Float) && intval intval * 100 else floatval = parse_value(val, :float) if floatval (floatval * 100).to_i else nil end end when :date then # Pull out the date part of the string and convert date_str = val.to_s.extract(/[0-9]+[\-\/][0-9]+[\-\/][0-9]+/) date_str.to_date rescue nil else raise "Unknown column type #{type.inspect} - unimplemented?" end end |