write_xlsx 1.11.0 → 1.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Changes +12 -0
- data/examples/shape_all.rb +1 -1
- data/lib/write_xlsx/chart/area.rb +1 -0
- data/lib/write_xlsx/chart/axis.rb +1 -0
- data/lib/write_xlsx/chart/bar.rb +1 -0
- data/lib/write_xlsx/chart/caption.rb +1 -0
- data/lib/write_xlsx/chart/column.rb +1 -0
- data/lib/write_xlsx/chart/doughnut.rb +1 -0
- data/lib/write_xlsx/chart/legend.rb +1 -0
- data/lib/write_xlsx/chart/line.rb +1 -0
- data/lib/write_xlsx/chart/pie.rb +15 -2
- data/lib/write_xlsx/chart/radar.rb +1 -0
- data/lib/write_xlsx/chart/scatter.rb +1 -0
- data/lib/write_xlsx/chart/series.rb +56 -4
- data/lib/write_xlsx/chart/stock.rb +1 -0
- data/lib/write_xlsx/chart.rb +107 -23
- data/lib/write_xlsx/chartsheet.rb +10 -1
- data/lib/write_xlsx/col_name.rb +7 -3
- data/lib/write_xlsx/colors.rb +20 -19
- data/lib/write_xlsx/format.rb +10 -8
- data/lib/write_xlsx/package/app.rb +9 -5
- data/lib/write_xlsx/package/comments.rb +2 -1
- data/lib/write_xlsx/package/conditional_format.rb +6 -6
- data/lib/write_xlsx/package/packager.rb +2 -3
- data/lib/write_xlsx/package/styles.rb +11 -13
- data/lib/write_xlsx/package/table.rb +74 -20
- data/lib/write_xlsx/package/xml_writer_simple.rb +32 -44
- data/lib/write_xlsx/sheets.rb +6 -2
- data/lib/write_xlsx/sparkline.rb +2 -2
- data/lib/write_xlsx/utility.rb +14 -12
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +2 -3
- data/lib/write_xlsx/worksheet/cell_data.rb +17 -18
- data/lib/write_xlsx/worksheet/hyperlink.rb +2 -2
- data/lib/write_xlsx/worksheet.rb +90 -39
- data/write_xlsx.gemspec +2 -0
- metadata +31 -3
| @@ -411,7 +411,7 @@ module Writexlsx | |
| 411 411 | 
             
                    # Check for a cell reference in A1 notation and substitute row and column
         | 
| 412 412 | 
             
                    user_range = if args[0].to_s =~ (/^\D/) && (args[0] =~ /,/)
         | 
| 413 413 | 
             
                                   # Check for a user defined multiple range like B3:K6,B8:K11.
         | 
| 414 | 
            -
                                   args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub( | 
| 414 | 
            +
                                   args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub("$", '')
         | 
| 415 415 | 
             
                                 end
         | 
| 416 416 |  | 
| 417 417 | 
             
                    if (row_col_array = row_col_notation(args.first))
         | 
| @@ -769,7 +769,7 @@ module Writexlsx | |
| 769 769 | 
             
                    attr = super
         | 
| 770 770 | 
             
                    attr << ['percent', 1]             if criteria == '%'
         | 
| 771 771 | 
             
                    attr << ['bottom',  1]             if direction
         | 
| 772 | 
            -
                    attr << ['rank',     | 
| 772 | 
            +
                    attr << ['rank',    value || 10]
         | 
| 773 773 | 
             
                    attr
         | 
| 774 774 | 
             
                  end
         | 
| 775 775 | 
             
                end
         | 
| @@ -818,9 +818,9 @@ module Writexlsx | |
| 818 818 | 
             
                      write_cfvo(min_type, min_value)
         | 
| 819 819 | 
             
                      write_cfvo(mid_type, mid_value) if mid_type
         | 
| 820 820 | 
             
                      write_cfvo(max_type, max_value)
         | 
| 821 | 
            -
                      write_color( | 
| 822 | 
            -
                      write_color( | 
| 823 | 
            -
                      write_color( | 
| 821 | 
            +
                      write_color('rgb', min_color)
         | 
| 822 | 
            +
                      write_color('rgb', mid_color)  if mid_color
         | 
| 823 | 
            +
                      write_color('rgb', max_color)
         | 
| 824 824 | 
             
                    end
         | 
| 825 825 | 
             
                  end
         | 
| 826 826 | 
             
                end
         | 
| @@ -844,7 +844,7 @@ module Writexlsx | |
| 844 844 | 
             
                      write_cfvo(min_type, min_value)
         | 
| 845 845 | 
             
                      write_cfvo(max_type, max_value)
         | 
| 846 846 |  | 
| 847 | 
            -
                      write_color( | 
| 847 | 
            +
                      write_color('rgb', bar_color)
         | 
| 848 848 | 
             
                    end
         | 
| 849 849 | 
             
                  end
         | 
| 850 850 |  | 
| @@ -142,13 +142,12 @@ module Writexlsx | |
| 142 142 | 
             
                  def write_app_file
         | 
| 143 143 | 
             
                    app = Package::App.new(@workbook)
         | 
| 144 144 |  | 
| 145 | 
            +
                    # Add the Worksheet parts.
         | 
| 146 | 
            +
                    app.add_worksheet_part_names
         | 
| 145 147 | 
             
                    # Add the Worksheet heading pairs.
         | 
| 146 148 | 
             
                    app.add_worksheet_heading_pairs
         | 
| 147 149 | 
             
                    # Add the Chartsheet heading pairs.
         | 
| 148 150 | 
             
                    app.add_chartsheet_heading_pairs
         | 
| 149 | 
            -
             | 
| 150 | 
            -
                    # Add the Worksheet parts.
         | 
| 151 | 
            -
                    app.add_worksheet_part_names
         | 
| 152 151 | 
             
                    # Add the Chartsheet parts.
         | 
| 153 152 | 
             
                    app.add_chartsheet_part_names
         | 
| 154 153 | 
             
                    # Add the Named Range heading pairs.
         | 
| @@ -59,6 +59,8 @@ module Writexlsx | |
| 59 59 | 
             
                  def palette_color(index)
         | 
| 60 60 | 
             
                    if index.to_s =~ /^#([0-9A-F]{6})$/i
         | 
| 61 61 | 
             
                      "FF#{::Regexp.last_match(1).upcase}"
         | 
| 62 | 
            +
                    elsif index == 0x40
         | 
| 63 | 
            +
                      "Automatic"
         | 
| 62 64 | 
             
                    else
         | 
| 63 65 | 
             
                      "FF#{super(index)}"
         | 
| 64 66 | 
             
                    end
         | 
| @@ -186,15 +188,6 @@ module Writexlsx | |
| 186 188 | 
             
                    end
         | 
| 187 189 | 
             
                  end
         | 
| 188 190 |  | 
| 189 | 
            -
                  #
         | 
| 190 | 
            -
                  # Write the <color> element.
         | 
| 191 | 
            -
                  #
         | 
| 192 | 
            -
                  def write_color(name, value)
         | 
| 193 | 
            -
                    attributes = [[name, value]]
         | 
| 194 | 
            -
             | 
| 195 | 
            -
                    @writer.empty_tag('color', attributes)
         | 
| 196 | 
            -
                  end
         | 
| 197 | 
            -
             | 
| 198 191 | 
             
                  #
         | 
| 199 192 | 
             
                  # Write the <fills> element.
         | 
| 200 193 | 
             
                  #
         | 
| @@ -284,10 +277,14 @@ module Writexlsx | |
| 284 277 | 
             
                  def write_pattern_fill(format, dxf_format)
         | 
| 285 278 | 
             
                    bg_color, fg_color = bg_and_fg_color(format, dxf_format)
         | 
| 286 279 |  | 
| 287 | 
            -
                     | 
| 280 | 
            +
                    if fg_color && fg_color != 0 && fg_color != 0x40  # 'Automatic'
         | 
| 281 | 
            +
                      @writer.empty_tag('fgColor', [['rgb', palette_color(fg_color)]])
         | 
| 282 | 
            +
                    end
         | 
| 288 283 |  | 
| 289 284 | 
             
                    if bg_color && bg_color != 0
         | 
| 290 | 
            -
                       | 
| 285 | 
            +
                      if bg_color != 0x40 # 'Automatic'
         | 
| 286 | 
            +
                        @writer.empty_tag('bgColor', [['rgb', palette_color(bg_color)]])
         | 
| 287 | 
            +
                      end
         | 
| 291 288 | 
             
                    elsif !dxf_format && format.pattern <= 1
         | 
| 292 289 | 
             
                      @writer.empty_tag('bgColor', [['indexed', 64]])
         | 
| 293 290 | 
             
                    end
         | 
| @@ -390,10 +387,11 @@ module Writexlsx | |
| 390 387 | 
             
                    attributes = [[:style, BORDER_STYLES[style]]]
         | 
| 391 388 |  | 
| 392 389 | 
             
                    @writer.tag_elements(type, attributes) do
         | 
| 393 | 
            -
                      if color  | 
| 390 | 
            +
                      if [0, 0x40].include?(color) # 'Automatic'
         | 
| 394 391 | 
             
                        @writer.empty_tag('color', [['auto', 1]])
         | 
| 395 | 
            -
                       | 
| 392 | 
            +
                      elsif color != 0 && color != 0x40 # 'Automatic'
         | 
| 396 393 | 
             
                        color = palette_color(color)
         | 
| 394 | 
            +
             | 
| 397 395 | 
             
                        @writer.empty_tag('color', [['rgb', color]])
         | 
| 398 396 | 
             
                      end
         | 
| 399 397 | 
             
                    end
         | 
| @@ -12,13 +12,14 @@ module Writexlsx | |
| 12 12 | 
             
                  class ColumnData
         | 
| 13 13 | 
             
                    attr_reader :id
         | 
| 14 14 | 
             
                    attr_accessor :name, :format, :formula, :name_format
         | 
| 15 | 
            -
                    attr_accessor :total_string, :total_function
         | 
| 15 | 
            +
                    attr_accessor :total_string, :total_function, :custom_total
         | 
| 16 16 |  | 
| 17 17 | 
             
                    def initialize(id, param = {})
         | 
| 18 18 | 
             
                      @id             = id
         | 
| 19 19 | 
             
                      @name           = "Column#{id}"
         | 
| 20 20 | 
             
                      @total_string   = ''
         | 
| 21 21 | 
             
                      @total_function = ''
         | 
| 22 | 
            +
                      @custom_total   = ''
         | 
| 22 23 | 
             
                      @formula        = ''
         | 
| 23 24 | 
             
                      @format         = nil
         | 
| 24 25 | 
             
                      @name_format    = nil
         | 
| @@ -51,6 +52,7 @@ module Writexlsx | |
| 51 52 |  | 
| 52 53 | 
             
                    add_the_table_columns
         | 
| 53 54 | 
             
                    write_the_cell_data_if_supplied
         | 
| 55 | 
            +
                    write_any_columns_formulas_after_the_user_supplied_table_data
         | 
| 54 56 | 
             
                    store_filter_cell_positions
         | 
| 55 57 | 
             
                  end
         | 
| 56 58 |  | 
| @@ -78,7 +80,7 @@ module Writexlsx | |
| 78 80 | 
             
                      # Set up the default column data.
         | 
| 79 81 | 
             
                      col_data = Package::Table::ColumnData.new(col_id + 1, @param[:columns])
         | 
| 80 82 |  | 
| 81 | 
            -
                       | 
| 83 | 
            +
                      overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
         | 
| 82 84 |  | 
| 83 85 | 
             
                      # Store the column data.
         | 
| 84 86 | 
             
                      @columns << col_data
         | 
| @@ -89,7 +91,7 @@ module Writexlsx | |
| 89 91 | 
             
                    end    # Table columns.
         | 
| 90 92 | 
             
                  end
         | 
| 91 93 |  | 
| 92 | 
            -
                  def  | 
| 94 | 
            +
                  def overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
         | 
| 93 95 | 
             
                    # Check if there are user defined values for this column.
         | 
| 94 96 | 
             
                    if @param[:columns] && (user_data = @param[:columns][col_id])
         | 
| 95 97 | 
             
                      # Map user defined values to internal values.
         | 
| @@ -156,6 +158,23 @@ module Writexlsx | |
| 156 158 | 
             
                    end
         | 
| 157 159 | 
             
                  end
         | 
| 158 160 |  | 
| 161 | 
            +
                  def write_any_columns_formulas_after_the_user_supplied_table_data
         | 
| 162 | 
            +
                    col_id = 0
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                    (@col1..@col2).each do |col|
         | 
| 165 | 
            +
                      column_data = @columns[col_id]
         | 
| 166 | 
            +
                      if ptrue?(column_data) && ptrue?(column_data.formula)
         | 
| 167 | 
            +
                        formula_format = @col_formats[col_id]
         | 
| 168 | 
            +
                        formula        = column_data.formula
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                        (@first_data_row..@last_data_row).each do |row|
         | 
| 171 | 
            +
                          @worksheet.write_formula(row, col, formula, formula_format)
         | 
| 172 | 
            +
                        end
         | 
| 173 | 
            +
                      end
         | 
| 174 | 
            +
                      col_id += 1
         | 
| 175 | 
            +
                    end
         | 
| 176 | 
            +
                  end
         | 
| 177 | 
            +
             | 
| 159 178 | 
             
                  def store_filter_cell_positions
         | 
| 160 179 | 
             
                    if ptrue?(@param[:autofilter])
         | 
| 161 180 | 
             
                      (@col1..@col2).each do |col|
         | 
| @@ -234,25 +253,45 @@ module Writexlsx | |
| 234 253 | 
             
                    ]
         | 
| 235 254 | 
             
                  end
         | 
| 236 255 |  | 
| 237 | 
            -
                  def handle_the_column_formula(col_data,  | 
| 256 | 
            +
                  def handle_the_column_formula(col_data, _col_num, formula, _format)
         | 
| 238 257 | 
             
                    return unless formula
         | 
| 239 258 |  | 
| 240 | 
            -
                     | 
| 259 | 
            +
                    formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
         | 
| 241 260 |  | 
| 242 | 
            -
                     | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 261 | 
            +
                    # Escape any future functions.
         | 
| 262 | 
            +
                    col_data.formula = @worksheet.prepare_formula(formula, 1)
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                    # (@first_data_row..@last_data_row).each do |row|
         | 
| 265 | 
            +
                    #   @worksheet.write_formula(row, col_num, col_data.formula, format)
         | 
| 266 | 
            +
                    # end
         | 
| 245 267 | 
             
                  end
         | 
| 246 268 |  | 
| 247 269 | 
             
                  def handle_the_function_for_the_table_row(row2, col_data, col_num, user_data)
         | 
| 248 | 
            -
                     | 
| 270 | 
            +
                    formula = ''
         | 
| 271 | 
            +
                    function = user_data[:total_function]
         | 
| 272 | 
            +
                    function = 'countNums' if function == 'count_nums'
         | 
| 273 | 
            +
                    function = 'stdDev'    if function == 'std_dev'
         | 
| 249 274 |  | 
| 250 | 
            -
                     | 
| 251 | 
            -
             | 
| 275 | 
            +
                    subtotals = {
         | 
| 276 | 
            +
                      average:   101,
         | 
| 277 | 
            +
                      countNums: 102,
         | 
| 278 | 
            +
                      count:     103,
         | 
| 279 | 
            +
                      max:       104,
         | 
| 280 | 
            +
                      min:       105,
         | 
| 281 | 
            +
                      stdDev:    106,
         | 
| 282 | 
            +
                      sum:       109,
         | 
| 283 | 
            +
                      var:       110
         | 
| 284 | 
            +
                    }
         | 
| 252 285 |  | 
| 253 | 
            -
                     | 
| 286 | 
            +
                    if subtotals[function.to_sym]
         | 
| 287 | 
            +
                      formula = table_function_to_formula(function, col_data.name)
         | 
| 288 | 
            +
                    else
         | 
| 289 | 
            +
                      formula = @worksheet.prepare_formula(function, 1)
         | 
| 290 | 
            +
                      col_data.custom_total = formula
         | 
| 291 | 
            +
                      function = 'custom'
         | 
| 292 | 
            +
                    end
         | 
| 254 293 |  | 
| 255 | 
            -
                     | 
| 294 | 
            +
                    col_data.total_function = function
         | 
| 256 295 | 
             
                    @worksheet.write_formula(row2, col_num, formula, user_data[:format], user_data[:total_value])
         | 
| 257 296 | 
             
                  end
         | 
| 258 297 |  | 
| @@ -260,10 +299,10 @@ module Writexlsx | |
| 260 299 | 
             
                  # Convert a table total function to a worksheet formula.
         | 
| 261 300 | 
             
                  #
         | 
| 262 301 | 
             
                  def table_function_to_formula(function, col_name)
         | 
| 263 | 
            -
                    col_name = col_name.gsub( | 
| 264 | 
            -
                                       .gsub( | 
| 265 | 
            -
                                       .gsub( | 
| 266 | 
            -
                                       .gsub( | 
| 302 | 
            +
                    col_name = col_name.gsub("'", "''")
         | 
| 303 | 
            +
                                       .gsub("#", "'#")
         | 
| 304 | 
            +
                                       .gsub("[", "'[")
         | 
| 305 | 
            +
                                       .gsub("]", "']")
         | 
| 267 306 |  | 
| 268 307 | 
             
                    subtotals = {
         | 
| 269 308 | 
             
                      average:   101,
         | 
| @@ -395,10 +434,16 @@ module Writexlsx | |
| 395 434 |  | 
| 396 435 | 
             
                    attributes << [:dataDxfId, col_data.format] if col_data.format
         | 
| 397 436 |  | 
| 398 | 
            -
                    if ptrue?(col_data.formula)
         | 
| 437 | 
            +
                    if ptrue?(col_data.formula) || ptrue?(col_data.custom_total)
         | 
| 399 438 | 
             
                      @writer.tag_elements('tableColumn', attributes) do
         | 
| 400 | 
            -
                         | 
| 401 | 
            -
             | 
| 439 | 
            +
                        if ptrue?(col_data.formula)
         | 
| 440 | 
            +
                          # Write the calculatedColumnFormula element.
         | 
| 441 | 
            +
                          write_calculated_column_formula(col_data.formula)
         | 
| 442 | 
            +
                        end
         | 
| 443 | 
            +
                        if ptrue?(col_data.custom_total)
         | 
| 444 | 
            +
                          # Write the totalsRowFormula element.
         | 
| 445 | 
            +
                          write_totals_row_formula(col_data.custom_total)
         | 
| 446 | 
            +
                        end
         | 
| 402 447 | 
             
                      end
         | 
| 403 448 | 
             
                    else
         | 
| 404 449 | 
             
                      @writer.empty_tag('tableColumn', attributes)
         | 
| @@ -425,6 +470,15 @@ module Writexlsx | |
| 425 470 | 
             
                  def write_calculated_column_formula(formula)
         | 
| 426 471 | 
             
                    @writer.data_element('calculatedColumnFormula', formula)
         | 
| 427 472 | 
             
                  end
         | 
| 473 | 
            +
             | 
| 474 | 
            +
                  #
         | 
| 475 | 
            +
                  # _write_totals_row_formula()
         | 
| 476 | 
            +
                  #
         | 
| 477 | 
            +
                  # Write the <totalsRowFormula> element.
         | 
| 478 | 
            +
                  #
         | 
| 479 | 
            +
                  def write_totals_row_formula(formula)
         | 
| 480 | 
            +
                    @writer.data_element('totalsRowFormula', formula)
         | 
| 481 | 
            +
                  end
         | 
| 428 482 | 
             
                end
         | 
| 429 483 | 
             
              end
         | 
| 430 484 | 
             
            end
         | 
| @@ -29,33 +29,28 @@ module Writexlsx | |
| 29 29 | 
             
                    io_write(str)
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 |  | 
| 32 | 
            -
                  def tag_elements(tag, attributes =  | 
| 32 | 
            +
                  def tag_elements(tag, attributes = nil)
         | 
| 33 33 | 
             
                    start_tag(tag, attributes)
         | 
| 34 34 | 
             
                    yield
         | 
| 35 35 | 
             
                    end_tag(tag)
         | 
| 36 36 | 
             
                  end
         | 
| 37 37 |  | 
| 38 | 
            -
                  def tag_elements_str(tag, attributes =  | 
| 38 | 
            +
                  def tag_elements_str(tag, attributes = nil)
         | 
| 39 39 | 
             
                    start_tag_str(tag, attributes) +
         | 
| 40 40 | 
             
                      yield +
         | 
| 41 41 | 
             
                      end_tag_str(tag)
         | 
| 42 42 | 
             
                  end
         | 
| 43 43 |  | 
| 44 | 
            -
                  def start_tag(tag, attr =  | 
| 44 | 
            +
                  def start_tag(tag, attr = nil)
         | 
| 45 45 | 
             
                    io_write(start_tag_str(tag, attr))
         | 
| 46 46 | 
             
                  end
         | 
| 47 47 |  | 
| 48 | 
            -
                  def start_tag_str(tag, attr =  | 
| 49 | 
            -
                    if attr.empty?
         | 
| 50 | 
            -
                       | 
| 51 | 
            -
                      unless result
         | 
| 52 | 
            -
                        result = "<#{tag}>"
         | 
| 53 | 
            -
                        @tag_start_cache[tag] = result
         | 
| 54 | 
            -
                      end
         | 
| 48 | 
            +
                  def start_tag_str(tag, attr = nil)
         | 
| 49 | 
            +
                    if attr.nil? || attr.empty?
         | 
| 50 | 
            +
                      @tag_start_cache[tag] ||= "<#{tag}>"
         | 
| 55 51 | 
             
                    else
         | 
| 56 | 
            -
                       | 
| 52 | 
            +
                      "<#{tag}#{key_vals(attr)}>"
         | 
| 57 53 | 
             
                    end
         | 
| 58 | 
            -
                    result
         | 
| 59 54 | 
             
                  end
         | 
| 60 55 |  | 
| 61 56 | 
             
                  def end_tag(tag)
         | 
| @@ -63,28 +58,15 @@ module Writexlsx | |
| 63 58 | 
             
                  end
         | 
| 64 59 |  | 
| 65 60 | 
             
                  def end_tag_str(tag)
         | 
| 66 | 
            -
                     | 
| 67 | 
            -
                    unless result
         | 
| 68 | 
            -
                      result = "</#{tag}>"
         | 
| 69 | 
            -
                      @tag_end_cache[tag] = result
         | 
| 70 | 
            -
                    end
         | 
| 71 | 
            -
                    result
         | 
| 61 | 
            +
                    @tag_end_cache[tag] ||= "</#{tag}>"
         | 
| 72 62 | 
             
                  end
         | 
| 73 63 |  | 
| 74 | 
            -
                  def empty_tag(tag, attr =  | 
| 64 | 
            +
                  def empty_tag(tag, attr = nil)
         | 
| 75 65 | 
             
                    str = "<#{tag}#{key_vals(attr)}/>"
         | 
| 76 66 | 
             
                    io_write(str)
         | 
| 77 67 | 
             
                  end
         | 
| 78 68 |  | 
| 79 | 
            -
                  def  | 
| 80 | 
            -
                    io_write(empty_tag_encoded_str(tag, attr))
         | 
| 81 | 
            -
                  end
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  def empty_tag_encoded_str(tag, attr = [])
         | 
| 84 | 
            -
                    "<#{tag}#{key_vals(attr)}/>"
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                  def data_element(tag, data, attr = [])
         | 
| 69 | 
            +
                  def data_element(tag, data, attr = nil)
         | 
| 88 70 | 
             
                    tag_elements(tag, attr) { io_write(escape_data(data)) }
         | 
| 89 71 | 
             
                  end
         | 
| 90 72 |  | 
| @@ -126,31 +108,37 @@ module Writexlsx | |
| 126 108 |  | 
| 127 109 | 
             
                  private
         | 
| 128 110 |  | 
| 129 | 
            -
                  def key_val(key, val)
         | 
| 130 | 
            -
                    %( #{key}="#{val}")
         | 
| 131 | 
            -
                  end
         | 
| 132 | 
            -
             | 
| 133 111 | 
             
                  def key_vals(attribute)
         | 
| 134 | 
            -
                    attribute
         | 
| 135 | 
            -
                       | 
| 112 | 
            +
                    if attribute
         | 
| 113 | 
            +
                      result = "".dup
         | 
| 114 | 
            +
                      attribute.each do |attr|
         | 
| 115 | 
            +
                        # Generate and concat %( #{key}="#{val}") values for attribute pair
         | 
| 116 | 
            +
                        result << " "
         | 
| 117 | 
            +
                        result << attr.first.to_s
         | 
| 118 | 
            +
                        result << '="'
         | 
| 119 | 
            +
                        result << escape_attributes(attr.last).to_s
         | 
| 120 | 
            +
                        result << '"'
         | 
| 121 | 
            +
                      end
         | 
| 122 | 
            +
                      result
         | 
| 123 | 
            +
                    end
         | 
| 136 124 | 
             
                  end
         | 
| 137 125 |  | 
| 138 126 | 
             
                  def escape_attributes(str = '')
         | 
| 139 | 
            -
                    return str unless str. | 
| 127 | 
            +
                    return str unless str.respond_to?(:match) && str =~ /["&<>\n]/
         | 
| 140 128 |  | 
| 141 129 | 
             
                    str
         | 
| 142 | 
            -
                      .gsub( | 
| 143 | 
            -
                      .gsub( | 
| 144 | 
            -
                      .gsub( | 
| 145 | 
            -
                      .gsub( | 
| 146 | 
            -
                      .gsub( | 
| 130 | 
            +
                      .gsub("&", "&")
         | 
| 131 | 
            +
                      .gsub('"', """)
         | 
| 132 | 
            +
                      .gsub("<", "<")
         | 
| 133 | 
            +
                      .gsub(">", ">")
         | 
| 134 | 
            +
                      .gsub("\n", "
")
         | 
| 147 135 | 
             
                  end
         | 
| 148 136 |  | 
| 149 137 | 
             
                  def escape_data(str = '')
         | 
| 150 | 
            -
                    if str. | 
| 151 | 
            -
                      str.gsub( | 
| 152 | 
            -
                         .gsub( | 
| 153 | 
            -
                         .gsub( | 
| 138 | 
            +
                    if str.respond_to?(:match) && str =~ /[&<>]/
         | 
| 139 | 
            +
                      str.gsub("&", '&')
         | 
| 140 | 
            +
                         .gsub("<", '<')
         | 
| 141 | 
            +
                         .gsub(">", '>')
         | 
| 154 142 | 
             
                    else
         | 
| 155 143 | 
             
                      str
         | 
| 156 144 | 
             
                    end
         | 
    
        data/lib/write_xlsx/sheets.rb
    CHANGED
    
    | @@ -252,9 +252,13 @@ module Writexlsx | |
| 252 252 | 
             
                    ['sheetId', sheet_id]
         | 
| 253 253 | 
             
                  ]
         | 
| 254 254 |  | 
| 255 | 
            -
                   | 
| 255 | 
            +
                  if sheet.hidden?
         | 
| 256 | 
            +
                    attributes << %w[state hidden]
         | 
| 257 | 
            +
                  elsif sheet.very_hidden?
         | 
| 258 | 
            +
                    attributes << %w[state veryHidden]
         | 
| 259 | 
            +
                  end
         | 
| 256 260 | 
             
                  attributes << r_id_attributes(sheet_id)
         | 
| 257 | 
            -
                  writer. | 
| 261 | 
            +
                  writer.empty_tag('sheet', attributes)
         | 
| 258 262 | 
             
                end
         | 
| 259 263 | 
             
              end
         | 
| 260 264 | 
             
            end
         | 
    
        data/lib/write_xlsx/sparkline.rb
    CHANGED
    
    | @@ -43,13 +43,13 @@ module Writexlsx | |
| 43 43 | 
             
                  # Cleanup the input ranges.
         | 
| 44 44 | 
             
                  @ranges.collect! do |range|
         | 
| 45 45 | 
             
                    # Remove the absolute reference $ symbols.
         | 
| 46 | 
            -
                    range = range.gsub( | 
| 46 | 
            +
                    range = range.gsub("$", '')
         | 
| 47 47 | 
             
                    # Convert a simple range into a full Sheet1!A1:D1 range.
         | 
| 48 48 | 
             
                    range = "#{sheetname}!#{range}" unless range =~ /!/
         | 
| 49 49 | 
             
                    range
         | 
| 50 50 | 
             
                  end
         | 
| 51 51 | 
             
                  # Cleanup the input locations.
         | 
| 52 | 
            -
                  @locations.collect! { |location| location.gsub( | 
| 52 | 
            +
                  @locations.collect! { |location| location.gsub("$", '') }
         | 
| 53 53 |  | 
| 54 54 | 
             
                  # Map options.
         | 
| 55 55 | 
             
                  @high      = param[:high_point]
         | 
    
        data/lib/write_xlsx/utility.rb
    CHANGED
    
    | @@ -31,10 +31,12 @@ module Writexlsx | |
| 31 31 | 
             
                #
         | 
| 32 32 | 
             
                # xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
         | 
| 33 33 | 
             
                #
         | 
| 34 | 
            -
                def xl_rowcol_to_cell( | 
| 35 | 
            -
                   | 
| 34 | 
            +
                def xl_rowcol_to_cell(row_or_name, col, row_absolute = false, col_absolute = false)
         | 
| 35 | 
            +
                  if row_or_name.is_a?(Integer)
         | 
| 36 | 
            +
                    row_or_name += 1      # Change from 0-indexed to 1 indexed.
         | 
| 37 | 
            +
                  end
         | 
| 36 38 | 
             
                  col_str = xl_col_to_name(col, col_absolute)
         | 
| 37 | 
            -
                  "#{col_str}#{absolute_char(row_absolute)}#{ | 
| 39 | 
            +
                  "#{col_str}#{absolute_char(row_absolute)}#{row_or_name}"
         | 
| 38 40 | 
             
                end
         | 
| 39 41 |  | 
| 40 42 | 
             
                #
         | 
| @@ -53,7 +55,7 @@ module Writexlsx | |
| 53 55 |  | 
| 54 56 | 
             
                  # Convert base26 column string to number
         | 
| 55 57 | 
             
                  # All your Base are belong to us.
         | 
| 56 | 
            -
                  chars = col.split( | 
| 58 | 
            +
                  chars = col.split("")
         | 
| 57 59 | 
             
                  expn = 0
         | 
| 58 60 | 
             
                  col = 0
         | 
| 59 61 |  | 
| @@ -112,7 +114,7 @@ module Writexlsx | |
| 112 114 | 
             
                #
         | 
| 113 115 | 
             
                def xl_string_pixel_width(string)
         | 
| 114 116 | 
             
                  length = 0
         | 
| 115 | 
            -
                  string.to_s.split( | 
| 117 | 
            +
                  string.to_s.split("").each { |char| length += CHAR_WIDTHS[char] || 8 }
         | 
| 116 118 |  | 
| 117 119 | 
             
                  length
         | 
| 118 120 | 
             
                end
         | 
| @@ -128,7 +130,7 @@ module Writexlsx | |
| 128 130 | 
             
                  name = sheetname.dup
         | 
| 129 131 | 
             
                  if name =~ /\W/ && !(name =~ /^'/)
         | 
| 130 132 | 
             
                    # Double quote and single quoted strings.
         | 
| 131 | 
            -
                    name = name.gsub( | 
| 133 | 
            +
                    name = name.gsub("'", "''")
         | 
| 132 134 | 
             
                    name = "'#{name}'"
         | 
| 133 135 | 
             
                  end
         | 
| 134 136 | 
             
                  name
         | 
| @@ -159,7 +161,7 @@ module Writexlsx | |
| 159 161 | 
             
                  seconds   = 0 # Time expressed as fraction of 24h hours in seconds
         | 
| 160 162 |  | 
| 161 163 | 
             
                  # Split into date and time.
         | 
| 162 | 
            -
                  date, time = date_time.split( | 
| 164 | 
            +
                  date, time = date_time.split("T")
         | 
| 163 165 |  | 
| 164 166 | 
             
                  # We allow the time portion of the input DateTime to be optional.
         | 
| 165 167 | 
             
                  if time
         | 
| @@ -207,7 +209,7 @@ module Writexlsx | |
| 207 209 | 
             
                  # becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
         | 
| 208 210 | 
             
                  #
         | 
| 209 211 | 
             
                  epoch   = date_1904? ? 1904 : 1900
         | 
| 210 | 
            -
                  offset  = date_1904? ? | 
| 212 | 
            +
                  offset  = date_1904? ? 4 : 0
         | 
| 211 213 | 
             
                  norm    = 300
         | 
| 212 214 | 
             
                  range   = year - epoch
         | 
| 213 215 |  | 
| @@ -248,7 +250,7 @@ module Writexlsx | |
| 248 250 | 
             
                def escape_url(url)
         | 
| 249 251 | 
             
                  unless url =~ /%[0-9a-fA-F]{2}/
         | 
| 250 252 | 
             
                    # Escape the URL escape symbol.
         | 
| 251 | 
            -
                    url = url.gsub( | 
| 253 | 
            +
                    url = url.gsub("%", "%25")
         | 
| 252 254 |  | 
| 253 255 | 
             
                    # Escape whitespae in URL.
         | 
| 254 256 | 
             
                    url = url.gsub(/[\s\x00]/, '%20')
         | 
| @@ -341,7 +343,7 @@ module Writexlsx | |
| 341 343 | 
             
                #
         | 
| 342 344 | 
             
                # Write the <color> element.
         | 
| 343 345 | 
             
                #
         | 
| 344 | 
            -
                def write_color( | 
| 346 | 
            +
                def write_color(name, value, writer = @writer) # :nodoc:
         | 
| 345 347 | 
             
                  attributes = [[name, value]]
         | 
| 346 348 |  | 
| 347 349 | 
             
                  writer.empty_tag('color', attributes)
         | 
| @@ -751,8 +753,8 @@ module Writexlsx | |
| 751 753 | 
             
                  # Adjust the colour index.
         | 
| 752 754 | 
             
                  idx = index - 8
         | 
| 753 755 |  | 
| 754 | 
            -
                   | 
| 755 | 
            -
                  sprintf("%02X%02X%02X",  | 
| 756 | 
            +
                  r, g, b = @palette[idx]
         | 
| 757 | 
            +
                  sprintf("%02X%02X%02X", r, g, b)
         | 
| 756 758 | 
             
                end
         | 
| 757 759 |  | 
| 758 760 | 
             
                #
         | 
    
        data/lib/write_xlsx/version.rb
    CHANGED
    
    
    
        data/lib/write_xlsx/workbook.rb
    CHANGED
    
    | @@ -715,7 +715,7 @@ module Writexlsx | |
| 715 715 |  | 
| 716 716 | 
             
                  # Split the cell range into 2 cells or else use single cell for both.
         | 
| 717 717 | 
             
                  if cells =~ /:/
         | 
| 718 | 
            -
                    cell_1, cell_2 = cells.split( | 
| 718 | 
            +
                    cell_1, cell_2 = cells.split(":")
         | 
| 719 719 | 
             
                  else
         | 
| 720 720 | 
             
                    cell_1 = cells
         | 
| 721 721 | 
             
                    cell_2 = cells
         | 
| @@ -724,7 +724,7 @@ module Writexlsx | |
| 724 724 | 
             
                  # Remove leading/trailing apostrophes and convert escaped quotes to single.
         | 
| 725 725 | 
             
                  sheetname.sub!(/^'/, '')
         | 
| 726 726 | 
             
                  sheetname.sub!(/'$/, '')
         | 
| 727 | 
            -
                  sheetname.gsub!( | 
| 727 | 
            +
                  sheetname.gsub!("''", "'")
         | 
| 728 728 |  | 
| 729 729 | 
             
                  row_start, col_start = xl_cell_to_rowcol(cell_1)
         | 
| 730 730 | 
             
                  row_end,   col_end   = xl_cell_to_rowcol(cell_2)
         | 
| @@ -988,7 +988,6 @@ module Writexlsx | |
| 988 988 | 
             
                  num_formats        = []
         | 
| 989 989 | 
             
                  unique_num_formats = {}
         | 
| 990 990 | 
             
                  index              = 164
         | 
| 991 | 
            -
                  num_format_count   = 0
         | 
| 992 991 |  | 
| 993 992 | 
             
                  (@xf_formats + @dxf_formats).each do |format|
         | 
| 994 993 | 
             
                    num_format = format.num_format
         | 
| @@ -1,6 +1,5 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            # frozen__literal: true
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 4 3 |  | 
| 5 4 | 
             
            module Writexlsx
         | 
| 6 5 | 
             
              class Worksheet
         | 
| @@ -13,10 +12,10 @@ module Writexlsx | |
| 13 12 | 
             
                  # attributes for the <cell> element. This is the innermost loop so efficiency is
         | 
| 14 13 | 
             
                  # important where possible.
         | 
| 15 14 | 
             
                  #
         | 
| 16 | 
            -
                  def cell_attributes(worksheet, row, col) # :nodoc:
         | 
| 15 | 
            +
                  def cell_attributes(worksheet, row, row_name, col) # :nodoc:
         | 
| 17 16 | 
             
                    xf_index = xf ? xf.get_xf_index : 0
         | 
| 18 17 | 
             
                    attributes = [
         | 
| 19 | 
            -
                      ['r', xl_rowcol_to_cell( | 
| 18 | 
            +
                      ['r', xl_rowcol_to_cell(row_name, col)]
         | 
| 20 19 | 
             
                    ]
         | 
| 21 20 |  | 
| 22 21 | 
             
                    # Add the cell format index.
         | 
| @@ -49,8 +48,8 @@ module Writexlsx | |
| 49 48 | 
             
                    @token
         | 
| 50 49 | 
             
                  end
         | 
| 51 50 |  | 
| 52 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 53 | 
            -
                    worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, col)) do
         | 
| 51 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 52 | 
            +
                    worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, row_name, col)) do
         | 
| 54 53 | 
             
                      worksheet.write_cell_value(token)
         | 
| 55 54 | 
             
                    end
         | 
| 56 55 | 
             
                  end
         | 
| @@ -70,8 +69,8 @@ module Writexlsx | |
| 70 69 | 
             
                  end
         | 
| 71 70 |  | 
| 72 71 | 
             
                  TYPE_STR_ATTRS = %w[t s].freeze
         | 
| 73 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 74 | 
            -
                    attributes = cell_attributes(worksheet, row, col)
         | 
| 72 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 73 | 
            +
                    attributes = cell_attributes(worksheet, row, row_name, col)
         | 
| 75 74 | 
             
                    attributes << TYPE_STR_ATTRS
         | 
| 76 75 | 
             
                    worksheet.writer.tag_elements('c', attributes) do
         | 
| 77 76 | 
             
                      worksheet.write_cell_value(token)
         | 
| @@ -102,11 +101,11 @@ module Writexlsx | |
| 102 101 | 
             
                    @result || 0
         | 
| 103 102 | 
             
                  end
         | 
| 104 103 |  | 
| 105 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 104 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 106 105 | 
             
                    truefalse = { 'TRUE' => 1, 'FALSE' => 0 }
         | 
| 107 106 | 
             
                    error_code = ['#DIV/0!', '#N/A', '#NAME?', '#NULL!', '#NUM!', '#REF!', '#VALUE!']
         | 
| 108 107 |  | 
| 109 | 
            -
                    attributes = cell_attributes(worksheet, row, col)
         | 
| 108 | 
            +
                    attributes = cell_attributes(worksheet, row, row_name, col)
         | 
| 110 109 | 
             
                    if @result && !(@result.to_s =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
         | 
| 111 110 | 
             
                      if truefalse[@result]
         | 
| 112 111 | 
             
                        attributes << %w[t b]
         | 
| @@ -138,8 +137,8 @@ module Writexlsx | |
| 138 137 | 
             
                    @result || 0
         | 
| 139 138 | 
             
                  end
         | 
| 140 139 |  | 
| 141 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 142 | 
            -
                    worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, col)) do
         | 
| 140 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 141 | 
            +
                    worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, row_name, col)) do
         | 
| 143 142 | 
             
                      worksheet.write_cell_array_formula(token, range)
         | 
| 144 143 | 
             
                      worksheet.write_cell_value(result)
         | 
| 145 144 | 
             
                    end
         | 
| @@ -160,9 +159,9 @@ module Writexlsx | |
| 160 159 | 
             
                    @result || 0
         | 
| 161 160 | 
             
                  end
         | 
| 162 161 |  | 
| 163 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 162 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 164 163 | 
             
                    # Add metadata linkage for dynamic array formulas.
         | 
| 165 | 
            -
                    attributes = cell_attributes(worksheet, row, col)
         | 
| 164 | 
            +
                    attributes = cell_attributes(worksheet, row, row_name, col)
         | 
| 166 165 | 
             
                    attributes << %w[cm 1]
         | 
| 167 166 |  | 
| 168 167 | 
             
                    worksheet.writer.tag_elements('c', attributes) do
         | 
| @@ -184,8 +183,8 @@ module Writexlsx | |
| 184 183 | 
             
                    @token
         | 
| 185 184 | 
             
                  end
         | 
| 186 185 |  | 
| 187 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 188 | 
            -
                    attributes = cell_attributes(worksheet, row, col)
         | 
| 186 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 187 | 
            +
                    attributes = cell_attributes(worksheet, row, row_name, col)
         | 
| 189 188 |  | 
| 190 189 | 
             
                    attributes << %w[t b]
         | 
| 191 190 | 
             
                    worksheet.writer.tag_elements('c', attributes) do
         | 
| @@ -203,8 +202,8 @@ module Writexlsx | |
| 203 202 | 
             
                    ''
         | 
| 204 203 | 
             
                  end
         | 
| 205 204 |  | 
| 206 | 
            -
                  def write_cell(worksheet, row, col)
         | 
| 207 | 
            -
                    worksheet.writer.empty_tag('c', cell_attributes(worksheet, row, col))
         | 
| 205 | 
            +
                  def write_cell(worksheet, row, row_name, col)
         | 
| 206 | 
            +
                    worksheet.writer.empty_tag('c', cell_attributes(worksheet, row, row_name, col))
         | 
| 208 207 | 
             
                  end
         | 
| 209 208 | 
             
                end
         | 
| 210 209 | 
             
              end
         |