lib/write_xlsx/package/table.rb in write_xlsx-1.11.1 vs lib/write_xlsx/package/table.rb in write_xlsx-1.11.2
- old
+ new
@@ -10,17 +10,18 @@
include Writexlsx::Utility
class ColumnData
attr_reader :id
attr_accessor :name, :format, :formula, :name_format
- attr_accessor :total_string, :total_function
+ attr_accessor :total_string, :total_function, :custom_total
def initialize(id, param = {})
@id = id
@name = "Column#{id}"
@total_string = ''
@total_function = ''
+ @custom_total = ''
@formula = ''
@format = nil
@name_format = nil
@user_data = param[id - 1] if param
end
@@ -49,10 +50,11 @@
set_the_table_and_autofilter_ranges
set_the_autofilter_range
add_the_table_columns
write_the_cell_data_if_supplied
+ write_any_columns_formulas_after_the_user_supplied_table_data
store_filter_cell_positions
end
def set_xml_writer(filename)
@writer.set_xml_writer(filename)
@@ -76,22 +78,22 @@
col_id = 0
(@col1..@col2).each do |col_num|
# Set up the default column data.
col_data = Package::Table::ColumnData.new(col_id + 1, @param[:columns])
- overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
+ overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
# Store the column data.
@columns << col_data
write_the_column_headers_to_the_worksheet(col_num, col_data)
col_id += 1
end # Table columns.
end
- def overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
+ def overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
# Check if there are user defined values for this column.
if @param[:columns] && (user_data = @param[:columns][col_id])
# Map user defined values to internal values.
col_data.name = user_data[:header] if user_data[:header] && !user_data[:header].empty?
@@ -154,10 +156,27 @@
end
i += 1
end
end
+ def write_any_columns_formulas_after_the_user_supplied_table_data
+ col_id = 0
+
+ (@col1..@col2).each do |col|
+ column_data = @columns[col_id]
+ if ptrue?(column_data) && ptrue?(column_data.formula)
+ formula_format = @col_formats[col_id]
+ formula = column_data.formula
+
+ (@first_data_row..@last_data_row).each do |row|
+ @worksheet.write_formula(row, col, formula, formula_format)
+ end
+ end
+ col_id += 1
+ end
+ end
+
def store_filter_cell_positions
if ptrue?(@param[:autofilter])
(@col1..@col2).each do |col|
@worksheet.filter_cells["#{@row1}:#{col}"] = 1
end
@@ -232,40 +251,60 @@
style
total_row
]
end
- def handle_the_column_formula(col_data, col_num, formula, format)
+ def handle_the_column_formula(col_data, _col_num, formula, _format)
return unless formula
- col_data.formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
+ formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
- (@first_data_row..@last_data_row).each do |row|
- @worksheet.write_formula(row, col_num, col_data.formula, format)
- end
+ # Escape any future functions.
+ col_data.formula = @worksheet.prepare_formula(formula, 1)
+
+ # (@first_data_row..@last_data_row).each do |row|
+ # @worksheet.write_formula(row, col_num, col_data.formula, format)
+ # end
end
def handle_the_function_for_the_table_row(row2, col_data, col_num, user_data)
- function = user_data[:total_function].downcase.gsub(/[_\s]/, '')
+ formula = ''
+ function = user_data[:total_function]
+ function = 'countNums' if function == 'count_nums'
+ function = 'stdDev' if function == 'std_dev'
- function = 'countNums' if function == 'countnums'
- function = 'stdDev' if function == 'stddev'
+ subtotals = {
+ average: 101,
+ countNums: 102,
+ count: 103,
+ max: 104,
+ min: 105,
+ stdDev: 106,
+ sum: 109,
+ var: 110
+ }
- col_data.total_function = function
+ if subtotals[function.to_sym]
+ formula = table_function_to_formula(function, col_data.name)
+ else
+ formula = @worksheet.prepare_formula(function, 1)
+ col_data.custom_total = formula
+ function = 'custom'
+ end
- formula = table_function_to_formula(function, col_data.name)
+ col_data.total_function = function
@worksheet.write_formula(row2, col_num, formula, user_data[:format], user_data[:total_value])
end
#
# Convert a table total function to a worksheet formula.
#
def table_function_to_formula(function, col_name)
- col_name = col_name.gsub(/'/, "''")
- .gsub(/#/, "'#")
- .gsub(/\[/, "'[")
- .gsub(/\]/, "']")
+ col_name = col_name.gsub("'", "''")
+ .gsub("#", "'#")
+ .gsub("[", "'[")
+ .gsub("]", "']")
subtotals = {
average: 101,
countNums: 102,
count: 103,
@@ -393,14 +432,20 @@
attributes << [:totalsRowFunction, col_data.total_function]
end
attributes << [:dataDxfId, col_data.format] if col_data.format
- if ptrue?(col_data.formula)
+ if ptrue?(col_data.formula) || ptrue?(col_data.custom_total)
@writer.tag_elements('tableColumn', attributes) do
- # Write the calculatedColumnFormula element.
- write_calculated_column_formula(col_data.formula)
+ if ptrue?(col_data.formula)
+ # Write the calculatedColumnFormula element.
+ write_calculated_column_formula(col_data.formula)
+ end
+ if ptrue?(col_data.custom_total)
+ # Write the totalsRowFormula element.
+ write_totals_row_formula(col_data.custom_total)
+ end
end
else
@writer.empty_tag('tableColumn', attributes)
end
end
@@ -422,9 +467,18 @@
#
# Write the <calculatedColumnFormula> element.
#
def write_calculated_column_formula(formula)
@writer.data_element('calculatedColumnFormula', formula)
+ end
+
+ #
+ # _write_totals_row_formula()
+ #
+ # Write the <totalsRowFormula> element.
+ #
+ def write_totals_row_formula(formula)
+ @writer.data_element('totalsRowFormula', formula)
end
end
end
end