require 'stockboy/reader'
require 'tempfile'
require 'roo'
require 'roo-xls'
module Stockboy::Readers
class Spreadsheet < Stockboy::Reader
dsl_attr :format
dsl_attr :sheet
dsl_attr :header_row
dsl_attr :first_row
dsl_attr :last_row
dsl_attr :headers
dsl_attr :options
def initialize(opts={}, &block)
super
@format = opts[:format] || :xls
@sheet = opts[:sheet] || :first
@first_row = opts[:first_row]
@last_row = opts[:last_row]
@header_row = opts[:header_row]
@headers = opts[:headers]
@options = opts[:options] || {}
DSL.new(self).instance_eval(&block) if block_given?
end
def parse(content)
with_spreadsheet_tempfile(content) do |table|
= (table)
enum_data_rows(table).inject([]) do |rows, i|
rows << Hash[.zip(table.row(i))]
end
end
end
private
def enum_data_rows(table)
first_table_row(table).upto last_table_row(table)
end
def with_spreadsheet_tempfile(content)
Tempfile.open(tmp_name, Stockboy.configuration.tmp_dir) do |file|
file.binmode
file.write content
file.fsync
table = Roo::Spreadsheet.open(file.path, @options)
table.default_sheet = sheet_number(table, @sheet)
table. = @header_row if @header_row
yield table
end
end
def sheet_number(table, id)
case id
when Symbol then table.sheets.public_send id
when Integer then table.sheets[id-1]
when String then id
end
end
def first_table_row(table)
return @first_row if @first_row
if @headers
table.first_row
elsif @header_row
@header_row + 1
else
table.first_row + 1
end
end
def last_table_row(table)
if @last_row.to_i < 0
table.last_row + @last_row + 1
elsif @last_row.to_i > 0
@last_row
else
table.last_row
end
end
def (table)
return @headers if @headers
table.row((table)).map { |h| h.to_s unless h.nil? }
end
def (table)
[table., table.first_row].max
end
def tmp_name
['stockboy', ".#{@format}"]
end
end
end