AXLSX merge cells inside a style
Yes give this a try (*Disclaimer I did not actually test these methods but I have used similar functionality in the past)
def merge_last_row(sheet,options ={})
last_row = sheet.rows.last.index + 1
first_col,last_col = options[:columns]
if first_col && last_col
sheet.merge_cells "#{first_col}#{last_row}:#{last_col}#{last_row}"
else
sheet.merge_cells sheet.rows.last
end
sheet.rows.last.style = style if options[:style]
end
so to do what you want it would be
merge_last_row sheet, columns:["A","E"]
sheet.add_row [I18n.t('foo.some_label').upcase]
merge_last_row sheet, columns:["B","E"], style:title
If the last row contains data in A-E then the columns can be left empty and it will merge the whole row. If it does not you could add an option for filling the columns like so
def fill_columns(sheet,column_count,options={})
row = options[:row_data] || []
(column_count - row.count).times do
row << nil
end
sheet.add_row row
end
calls as
my_row = ["Hello","World"]
fill_columns sheet, 5,row_data: my_row
# this will add a row like["Hello","World",nil,nil,nil]
# so that it will merge properly across the columns A-E
merge_last_row sheet
If you are going to use these consistently then patching these functions into Worksheet
might make more sense so you don't have to pass the sheet
object.
module Axlsx
class Worksheet
def merge_last_row(options={})
last_row = rows.last.index + 1
first_col,last_col = options[:columns]
if first_col && last_col
merge_cells "#{first_col}#{last_row}:#{last_col}#{last_row}"
else
merge_cells rows.last
end
rows.last.style = style if options[:style]
end
def fill_columns(column_count,options={})
row_data = options[:row_data] || []
(column_count - row.count).times do
row_data << nil
end
add_row row_data
end
end
end
Call
sheet.merge_last_row columns:["A","E"]
sheet.add_row [I18n.t('foo.some_label').upcase]
sheet.merge_last_row columns:["B","E"], style:title
Axlsx merge cells based on row-column number like in Spreadsheet gem
Probably the easiest way is to pass in the actual cells (untested):
merge_cells sheet.rows.last.cells[(1..2)]
merge_cells sheet.rows.last.cells[(3..4)]
But you can also use the Axlsx::col_ref
or Axlsx::cell_r
method to convert row, column
to the spreadsheet notation:
merge_cells Axlsx::cell_r(0,0) + ':' + Axlsx::cell_r(1,0)
merge_cells Axlsx::cell_r(2,0) + ':' + Axlsx::cell_r(3,0)
Edit
Regarding your issue of having to initialize strings, I am able to merge uninitialized cells, and specify merge before cells are specified. I am using Axlsx 2.0.1.
Applying several styles to a cell in Excel spreadsheet with AXLSX gem
I've managed to overlay cell styles by monkey patching Axlsx
classes. The idea is to first apply raw styles to cell in the form of Ruby hashes. When that is finished one can generate Axlsx
styles for the workbook and apply them. I can now separate the markup from style, having the styles applied as
sheet["B2:D2"].add_style(b: true)
sheet["B2:D5"].add_style(bg_color: "E2D3EB")
workbook.apply_styles
Below is the full listing of my hacky solution. This doesn't include identifying unique styles among other things that should be done in professional code. Looking forward to any feedback.
require 'axlsx'
class Array
def add_style(style)
return unless map{ |e| e.kind_of? Axlsx::Cell }.uniq.first
each { |cell| cell.add_style(style) }
end
end
class Axlsx::Workbook
attr_accessor :styled_cells
def add_styled_cell(cell)
self.styled_cells ||= []
self.styled_cells << cell
end
def apply_styles
return unless styled_cells
styled_cells.each do |cell|
cell.style = styles.add_style(cell.raw_style)
end
end
end
class Axlsx::Cell
attr_accessor :raw_style
def workbook
row.worksheet.workbook
end
def add_style(style)
self.raw_style ||= {}
self.raw_style = raw_style.merge(style)
workbook.add_styled_cell(self)
end
end
axlsx = Axlsx::Package.new
workbook = axlsx.workbook
workbook.add_worksheet do |sheet|
sheet.add_row
sheet.add_row ["", "Product", "Category", "Price"]
sheet.add_row ["", "Butter", "Dairy", 4.99]
sheet.add_row ["", "Bread", "Baked Goods", 3.45]
sheet.add_row ["", "Broccoli", "Produce", 2.99]
sheet["B2:D2"].add_style(b: true)
sheet["B2:D5"].add_style(bg_color: "E2D3EB")
end
workbook.apply_styles
axlsx.serialize "grocery.xlsx"
Edit: I've leaned up my solution and extracted it into a gem https://github.com/sakovias/axlsx_styler
Ruby Axlsx Gem Unlocking style on whole column
To do this you can use Worksheet#col_style
signature is col_style(index,style,options={})
index
The index of the row you want to set the style on (indexing starts at 0). Also index can be a range so if you want to unlock columns A though C then sheet.col_style((0..2),unlocked)
will still work appropriately based on the way the code functions.
style
must be a predefined style as it is in the rest of the gem
options ={}
options
allows you to set a row offset so if you didn't want to unlock the top n rows you could pass row_offset: n
and all the cells in the column after n
rows would be unlocked.
Example:
#unlock cells in column A starting at A3
sheet.col_style(0,unlocked,row_offset: 2)
Full Example
require 'axlsx'
p = Axlsx::Package.new
wb = p.workbook
unlocked = wb.styles.add_style(locked: false)
wb.add_worksheet do |sheet|
5.times { sheet.add_row [1,2,3,4,5,6]}
sheet.col_style(3,unlocked)
end
p.serialize('/simple_test.xlsx')
This will create a spreadsheet with 6 columns and the column with 4's (indexing starts at 0) will be unlocked while the rest of the columns remain locked (default).
Additional Info
The return value from this method will be a flat Array
of the cells affected.
Note: the code does pretty much exactly what you are doing in your loop. It collects all the cells and then applies the style to each cell in a loop.
Related Topics
Consequences of Implementing To_Int and To_Str in Ruby
Rails 3 Cli Executes Commands Really Slow
Opening Several Threads with Watir-Webdriver Results in 'Connection Refused' Error
Why Ruby Inject Method Cannot Sum Up String Lengths Without Initial Value
How to Serialize an Object Using Tcpserver Inside
Ruby: Converting from Float to Integer in Ruby Produces Strange Results
Problem Installing SQLite3-Ruby!
Uploading Files in Ruby on Rails
Ruby/Pgsql Error on Rails Start:Cannot Load Such File -- Pg_Ext (Loaderror)
Creating a Setter Method That Takes Extra Arguments in Ruby
Version Sort (With Alphas, Betas, etc.) in Ruby