class SeeAsVee::Sheet
Constants
- CELL_ERROR_MARKER
- CELL_ERROR_STYLE
- LEAVE_ERROR_MARKER
- WORK_SHEET_NAME
Attributes
checkers[R]
formatters[R]
rows[R]
Public Class Methods
new(whatever, formatters: {})
click to toggle source
# File lib/see_as_vee/sheet.rb, line 17 def initialize whatever, formatters: {}, checkers: {}, skip_blank_rows: false @formatters = formatters.map { |k, v| [str_to_sym(k), v] }.to_h @checkers = checkers.map { |k, v| [str_to_sym(k), v] }.to_h @rows = whatever.is_a?(Array) ? whatever : Helpers.harvest_csv(whatever) @rows = @rows.map do |row| row unless skip_blank_rows && row.compact.empty? end.compact.map.with_index do |row, idx| idx.zero? ? row : plough_row(row) end end
Public Instance Methods
[](index, key = nil)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 44 def [] index, key = nil key.nil? ? values[index] : values[index][header_index(key)] end
each() { |idx, errors, result| ... }
click to toggle source
# File lib/see_as_vee/sheet.rb, line 48 def each return enum_for unless block_given? values.each_with_index do |row, idx| result = headers.zip(row).to_h errors = result.select { |_, v| malformed?(v) } yield idx, errors, result end end
headers(symbolic = false)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 33 def headers symbolic = false headers = @rows.first unless headers.uniq.length == headers.length groups = headers.group_by { |h| h }.select { |_, group| group.size > 1 } headers = headers.map.with_index { |e, idx| groups[e].nil? ? e : "#{e} #{idx}" } end headers = headers.map.with_index { |s, ind| str_to_sym(s || "col #{ind}") } if symbolic headers end
map() { |headers(true).zip(row).to_h| ... }
click to toggle source
# File lib/see_as_vee/sheet.rb, line 58 def map return enum_for unless block_given? values.map do |row| yield headers(true).zip(row).to_h end end
produce(csv: true, xlsx: nil, **params)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 66 def produce csv: true, xlsx: nil, **params [csv && produce_csv(**params), xlsx && produce_xlsx(**params)] end
values()
click to toggle source
# File lib/see_as_vee/sheet.rb, line 29 def values @rows[1..-1] end
Private Instance Methods
check_cell(cell, i)
click to toggle source
rubocop:disable Style/MultilineTernaryOperator
# File lib/see_as_vee/sheet.rb, line 141 def check_cell cell, i f = @checkers[headers(true)[i]] case f when Proc then f.call(cell) when Symbol then cell.public_send(f) else true end ? cell : CELL_ERROR_MARKER + cell.to_s.split('').map { |c| "#{c}\u0336" }.join end
format_cell(cell, i)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 132 def format_cell cell, i case f = @formatters[headers(true)[i]] when Proc then f.call(cell) when Symbol then cell.public_send f else cell end end
header_index(key)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 114 def header_index key headers(true).index(str_to_sym(key)) end
malformed?(str)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 72 def malformed? str str.to_s.start_with? CELL_ERROR_MARKER end
plough_row(row)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 122 def plough_row row return row if @formatters.empty? && @checkers.empty? # performance row.map.with_index do |cell, i| cell = format_cell(cell, i) unless @formatters.empty? cell = check_cell(cell, i) unless @checkers.empty? cell end end
produce_csv(**params)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 76 def produce_csv **params return if @rows.empty? for_ms_excel = params.delete(:ms_excel) == true params.merge!(col_sep: "\t") if for_ms_excel Tempfile.open(['see_as_vee', '.csv']).tap do |f| content = CSV.generate(params) do |csv| @rows.each { |row| csv << row } end content = "\xFF\xFE".force_encoding(Encoding::UTF_16LE) << content.encode(Encoding::UTF_16LE) if for_ms_excel mode = for_ms_excel ? "w:UTF-16LE" : "w:UTF-8" File.open(f.path, mode) { |f| f.write content } end end
produce_xlsx(**params)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 97 def produce_xlsx **params params, axlsx_params = split_params(params) Tempfile.new(['see_as_vee', '.xlsx']).tap do |f| Axlsx::Package.new do |p| red = p.workbook.styles.add_style(**params[:ces]) if params[:ces].is_a?(Hash) p.workbook.add_worksheet(**axlsx_params) do |sheet| @rows.each do |row| styles = row.map { |cell| malformed?(cell) ? red : nil } row = row.map { |cell| malformed?(cell) ? cell.to_s.gsub(/\A#{CELL_ERROR_MARKER}/, '') : cell } if params[:lem] sheet.add_row row, style: styles end end p.serialize(f.path) end end end
split_params(params)
click to toggle source
rubocop:enable Style/MultilineTernaryOperator
# File lib/see_as_vee/sheet.rb, line 151 def split_params params params = params.dup [ { ces: params.delete(:cell_error_style) { CELL_ERROR_STYLE.dup }, lem: params.delete(:leave_error_marker) { LEAVE_ERROR_MARKER } }, { name: WORK_SHEET_NAME }.merge(params) ] end
squish(str)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 160 def squish str return str unless str.is_a?(String) str. gsub(/\A[[:space:]]+/, ''). gsub(/[[:space:]]+\z/, ''). gsub(/[[:space:]]+/, ' ') end
str_to_sym(str)
click to toggle source
# File lib/see_as_vee/sheet.rb, line 118 def str_to_sym str str.is_a?(Symbol) ? str : squish(str).downcase.gsub(/\W/, '_').to_sym end