lib/write_xlsx/utility.rb in write_xlsx-1.09.4 vs lib/write_xlsx/utility.rb in write_xlsx-1.09.5
- old
+ new
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# frozen_string_literal: true
+
require 'write_xlsx/col_name'
module Writexlsx
module Utility
ROW_MAX = 1048576 # :nodoc:
@@ -25,31 +26,31 @@
# mainly used internally and aren't very useful to the user.
#
def xl_cell_to_rowcol(cell)
cell =~ /(\$?)([A-Z]{1,3})(\$?)(\d+)/
- col_abs = $1 != ""
- col = $2
- row_abs = $3 != ""
- row = $4.to_i
+ col_abs = ::Regexp.last_match(1) != ""
+ col = ::Regexp.last_match(2)
+ row_abs = ::Regexp.last_match(3) != ""
+ row = ::Regexp.last_match(4).to_i
# Convert base26 column string to number
# All your Base are belong to us.
chars = col.split(//)
expn = 0
col = 0
chars.reverse.each do |char|
- col += (char.ord - 'A'.ord + 1) * (26 ** expn)
+ col += (char.ord - 'A'.ord + 1) * (26**expn)
expn += 1
end
# Convert 1-index to zero-index
row -= 1
col -= 1
- return [row, col, row_abs, col_abs]
+ [row, col, row_abs, col_abs]
end
def xl_col_to_name(col, col_absolute)
col_str = ColName.instance.col_str(col)
"#{absolute_char(col_absolute)}#{col_str}"
@@ -70,22 +71,22 @@
def xl_range_formula(sheetname, row_1, row_2, col_1, col_2)
# Use Excel's conventions and quote the sheet name if it contains any
# non-word character or if it isn't already quoted.
sheetname = "'#{sheetname}'" if sheetname =~ /\W/ && !(sheetname =~ /^'/)
- range1 = xl_rowcol_to_cell( row_1, col_1, 1, 1 )
- range2 = xl_rowcol_to_cell( row_2, col_2, 1, 1 )
+ range1 = xl_rowcol_to_cell(row_1, col_1, 1, 1)
+ range2 = xl_rowcol_to_cell(row_2, col_2, 1, 1)
"=#{sheetname}!#{range1}:#{range2}"
end
#
# Sheetnames used in references should be quoted if they contain any spaces,
# special characters or if the look like something that isn't a sheet name.
# TODO. We need to handle more special cases.
#
- def quote_sheetname(sheetname) #:nodoc:
+ def quote_sheetname(sheetname) # :nodoc:
# Use Excel's conventions and quote the sheet name if it comtains any
# non-word character or if it isn't already quoted.
name = sheetname.dup
if name =~ /\W/ && !(name =~ /^'/)
# Double quote and single quoted strings.
@@ -94,27 +95,26 @@
end
name
end
def check_dimensions(row, col)
- if !row || row >= ROW_MAX || !col || col >= COL_MAX
- raise WriteXLSXDimensionError
- end
+ raise WriteXLSXDimensionError if !row || row >= ROW_MAX || !col || col >= COL_MAX
+
0
end
#
# convert_date_time(date_time_string)
#
# The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format
# and converts it to a decimal number representing a valid Excel date.
#
- def convert_date_time(date_time_string) #:nodoc:
+ def convert_date_time(date_time_string) # :nodoc:
date_time = date_time_string.to_s.sub(/^\s+/, '').sub(/\s+$/, '').sub(/Z$/, '')
# Check for invalid date char.
- return nil if date_time =~ /[^0-9T:\-\.Z]/
+ return nil if date_time =~ /[^0-9T:\-.Z]/
# Check for "T" after date or before time.
return nil unless date_time =~ /\dT|T\d/
days = 0 # Number of days since epoch
@@ -125,34 +125,34 @@
# We allow the time portion of the input DateTime to be optional.
if time
# Match hh:mm:ss.sss+ where the seconds are optional
if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
- hour = $1.to_i
- min = $2.to_i
- sec = $4.to_f || 0
+ hour = ::Regexp.last_match(1).to_i
+ min = ::Regexp.last_match(2).to_i
+ sec = ::Regexp.last_match(4).to_f || 0
else
return nil # Not a valid time format.
end
# Some boundary checks
return nil if hour >= 24
return nil if min >= 60
return nil if sec >= 60
# Excel expresses seconds as a fraction of the number in 24 hours.
- seconds = (hour * 60* 60 + min * 60 + sec) / (24.0 * 60 * 60)
+ seconds = ((hour * 60 * 60) + (min * 60) + sec) / (24.0 * 60 * 60)
end
# We allow the date portion of the input DateTime to be optional.
return seconds if date == ''
# Match date as yyyy-mm-dd.
if date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/
- year = $1.to_i
- month = $2.to_i
- day = $3.to_i
+ year = ::Regexp.last_match(1).to_i
+ month = ::Regexp.last_match(2).to_i
+ day = ::Regexp.last_match(3).to_i
else
return nil # Not a valid date format.
end
# Set the epoch as 1900 or 1904. Defaults to 1900.
@@ -161,11 +161,10 @@
return seconds if date == '1899-12-31' # Excel 1900 epoch
return seconds if date == '1900-01-00' # Excel 1900 epoch
return 60 + seconds if date == '1900-02-29' # Excel false leapday
end
-
# We calculate the date by calculating the number of days since the epoch
# and adjust for the number of leap days. We calculate the number of leap
# days by normalising the year in relation to the epoch. Thus the year 2000
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
#
@@ -175,27 +174,27 @@
range = year - epoch
# Set month days and check for leap year.
mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
leap = 0
- leap = 1 if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
- mdays[1] = 29 if leap != 0
+ leap = 1 if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
+ mdays[1] = 29 if leap != 0
# Some boundary checks
return nil if year < epoch or year > 9999
return nil if month < 1 or month > 12
return nil if day < 1 or day > mdays[month - 1]
# Accumulate the number of days since the epoch.
days = day # Add days for current month
- (0 .. month-2).each do |m|
+ (0..month - 2).each do |m|
days += mdays[m] # Add days for past months
end
days += range * 365 # Add days for past years
- days += ((range) / 4) # Add leapdays
- days -= ((range + offset) /100) # Subtract 100 year leapdays
- days += ((range + offset + norm)/400) # Add 400 year leapdays
+ days += (range / 4) # Add leapdays
+ days -= ((range + offset) / 100) # Subtract 100 year leapdays
+ days += ((range + offset + norm) / 400) # Add 400 year leapdays
days -= leap # Already counted above
# Adjust for Excel erroneously treating 1900 as a leap year.
days += 1 if !date_1904? and days > 59
@@ -239,18 +238,19 @@
if FileTest.file?(path)
File.delete(path)
elsif FileTest.directory?(path)
Dir.foreach(path) do |file|
next if file =~ /^\.\.?$/ # '.' or '..'
- delete_files(path.sub(/\/+$/,"") + '/' + file)
+
+ delete_files(path.sub(%r{/+$}, "") + '/' + file)
end
Dir.rmdir(path)
end
end
def put_deprecate_message(method)
- $stderr.puts("Warning: calling deprecated method #{method}. This method will be removed in a future release.")
+ warn("Warning: calling deprecated method #{method}. This method will be removed in a future release.")
end
# Check for a cell reference in A1 notation and substitute row and column
def row_col_notation(args) # :nodoc:
if args[0].to_s =~ /^\D/
@@ -264,52 +264,52 @@
# Substitute an Excel cell reference in A1 notation for zero based row and
# column values in an argument list.
#
# Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
#
- def substitute_cellref(cell, *args) #:nodoc:
+ def substitute_cellref(cell, *args) # :nodoc:
return [*args] if cell.respond_to?(:coerce) # Numeric
normalized_cell = cell.upcase
case normalized_cell
# Convert a column range: 'A:A' or 'B:G'.
# A range such as A:A is equivalent to A1:65536, so add rows as required
when /\$?([A-Z]{1,3}):\$?([A-Z]{1,3})/
- row1, col1 = xl_cell_to_rowcol($1 + '1')
- row2, col2 = xl_cell_to_rowcol($2 + ROW_MAX.to_s)
- return [row1, col1, row2, col2, *args]
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1) + '1')
+ row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2) + ROW_MAX.to_s)
+ [row1, col1, row2, col2, *args]
# Convert a cell range: 'A1:B7'
when /\$?([A-Z]{1,3}\$?\d+):\$?([A-Z]{1,3}\$?\d+)/
- row1, col1 = xl_cell_to_rowcol($1)
- row2, col2 = xl_cell_to_rowcol($2)
- return [row1, col1, row2, col2, *args]
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
+ row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2))
+ [row1, col1, row2, col2, *args]
# Convert a cell reference: 'A1' or 'AD2000'
when /\$?([A-Z]{1,3}\$?\d+)/
- row1, col1 = xl_cell_to_rowcol($1)
- return [row1, col1, *args]
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
+ [row1, col1, *args]
else
raise("Unknown cell reference #{normalized_cell}")
end
end
def underline_attributes(underline)
if underline == 2
- [['val', 'double']]
+ [%w[val double]]
elsif underline == 33
- [['val', 'singleAccounting']]
+ [%w[val singleAccounting]]
elsif underline == 34
- [['val', 'doubleAccounting']]
+ [%w[val doubleAccounting]]
else
[] # Default to single underline.
end
end
#
# Write the <color> element.
#
- def write_color(writer, name, value) #:nodoc:
+ def write_color(writer, name, value) # :nodoc:
attributes = [[name, value]]
writer.empty_tag('color', attributes)
end
@@ -327,20 +327,20 @@
def check_parameter(params, valid_keys, method)
invalids = params.keys - valid_keys
unless invalids.empty?
raise WriteXLSXOptionParameterError,
- "Unknown parameter '#{invalids.join(', ')}' in #{method}."
+ "Unknown parameter '#{invalids.join(", ")}' in #{method}."
end
true
end
#
# Check that row and col are valid and store max and min values for use in
# other methods/elements.
#
- def check_dimensions_and_update_max_min_values(row, col, ignore_row = 0, ignore_col = 0) #:nodoc:
+ def check_dimensions_and_update_max_min_values(row, col, ignore_row = 0, ignore_col = 0) # :nodoc:
check_dimensions(row, col)
store_row_max_min_values(row) if ignore_row == 0
store_col_max_min_values(col) if ignore_col == 0
0
@@ -356,10 +356,11 @@
@dim_colmax = col if !@dim_colmax || (col > @dim_colmax)
end
def float_to_str(float)
return '' unless float
+
if float == float.to_i
float.to_i.to_s
else
float.to_s
end
@@ -377,21 +378,17 @@
# Set the legend layout.
legend.layout = layout_properties(params[:layout])
# Turn off the legend.
- if params[:none]
- legend.position = 'none'
- end
+ legend.position = 'none' if params[:none]
# Set the line properties for the legend.
line = line_properties(params[:line])
# Allow 'border' as a synonym for 'line'.
- if params[:border]
- line = line_properties(params[:border])
- end
+ line = line_properties(params[:border]) if params[:border]
# Set the fill properties for the legend.
fill = fill_properties(params[:fill])
# Set the pattern properties for the legend.
@@ -399,13 +396,11 @@
# Set the gradient fill properties for the legend.
gradient = gradient_properties(params[:gradient])
# Pattern fill overrides solid fill.
- if pattern
- fill = nil
- end
+ fill = nil if pattern
# Gradient fill overrides solid and pattern fills.
if gradient
pattern = nil
fill = nil
@@ -427,21 +422,19 @@
# Convert user defined layout properties to the format required internally.
#
def layout_properties(args, is_text = false)
return unless ptrue?(args)
- properties = is_text ? [:x, :y] : [:x, :y, :width, :height]
+ properties = is_text ? %i[x y] : %i[x y width height]
# Check for valid properties.
args.keys.each do |key|
- unless properties.include?(key.to_sym)
- raise "Property '#{key}' not allowed in layout options\n"
- end
+ raise "Property '#{key}' not allowed in layout options\n" unless properties.include?(key.to_sym)
end
# Set the layout properties
- layout = Hash.new
+ layout = {}
properties.each do |property|
value = args[property]
# Convert to the format used by Excel for easier testing.
layout[property] = sprintf("%.17g", value)
end
@@ -451,12 +444,12 @@
#
# Convert vertices from pixels to points.
#
def pixels_to_points(vertices)
- col_start, row_start, x1, y1,
- col_end, row_end, x2, y2,
+ _col_start, _row_start, _x1, _y1,
+ _col_end, _row_end, _x2, _y2,
left, top, width, height = vertices.flatten
left *= 0.75
top *= 0.75
width *= 0.75
@@ -512,11 +505,11 @@
# Write the <v:path> element.
#
def write_comment_path(gradientshapeok, connecttype)
attributes = []
- attributes << ['gradientshapeok', 't'] if gradientshapeok
+ attributes << %w[gradientshapeok t] if gradientshapeok
attributes << ['o:connecttype', connecttype]
@writer.empty_tag('v:path', attributes)
end
@@ -571,11 +564,11 @@
#
# Write the <v:stroke> element.
#
def write_stroke
- attributes = [['joinstyle', 'miter']]
+ attributes = [%w[joinstyle miter]]
@writer.empty_tag('v:stroke', attributes)
end
def r_id_attributes(id)
@@ -618,65 +611,65 @@
# Check the foreground color is present.
retuen nil unless args.has_key?(:fg_color)
types = {
- 'percent_5' => 'pct5',
- 'percent_10' => 'pct10',
- 'percent_20' => 'pct20',
- 'percent_25' => 'pct25',
- 'percent_30' => 'pct30',
- 'percent_40' => 'pct40',
+ 'percent_5' => 'pct5',
+ 'percent_10' => 'pct10',
+ 'percent_20' => 'pct20',
+ 'percent_25' => 'pct25',
+ 'percent_30' => 'pct30',
+ 'percent_40' => 'pct40',
- 'percent_50' => 'pct50',
- 'percent_60' => 'pct60',
- 'percent_70' => 'pct70',
- 'percent_75' => 'pct75',
- 'percent_80' => 'pct80',
- 'percent_90' => 'pct90',
+ 'percent_50' => 'pct50',
+ 'percent_60' => 'pct60',
+ 'percent_70' => 'pct70',
+ 'percent_75' => 'pct75',
+ 'percent_80' => 'pct80',
+ 'percent_90' => 'pct90',
- 'light_downward_diagonal' => 'ltDnDiag',
- 'light_upward_diagonal' => 'ltUpDiag',
- 'dark_downward_diagonal' => 'dkDnDiag',
- 'dark_upward_diagonal' => 'dkUpDiag',
- 'wide_downward_diagonal' => 'wdDnDiag',
- 'wide_upward_diagonal' => 'wdUpDiag',
+ 'light_downward_diagonal' => 'ltDnDiag',
+ 'light_upward_diagonal' => 'ltUpDiag',
+ 'dark_downward_diagonal' => 'dkDnDiag',
+ 'dark_upward_diagonal' => 'dkUpDiag',
+ 'wide_downward_diagonal' => 'wdDnDiag',
+ 'wide_upward_diagonal' => 'wdUpDiag',
- 'light_vertical' => 'ltVert',
- 'light_horizontal' => 'ltHorz',
- 'narrow_vertical' => 'narVert',
- 'narrow_horizontal' => 'narHorz',
- 'dark_vertical' => 'dkVert',
- 'dark_horizontal' => 'dkHorz',
+ 'light_vertical' => 'ltVert',
+ 'light_horizontal' => 'ltHorz',
+ 'narrow_vertical' => 'narVert',
+ 'narrow_horizontal' => 'narHorz',
+ 'dark_vertical' => 'dkVert',
+ 'dark_horizontal' => 'dkHorz',
- 'dashed_downward_diagonal' => 'dashDnDiag',
- 'dashed_upward_diagonal' => 'dashUpDiag',
- 'dashed_horizontal' => 'dashHorz',
- 'dashed_vertical' => 'dashVert',
- 'small_confetti' => 'smConfetti',
- 'large_confetti' => 'lgConfetti',
+ 'dashed_downward_diagonal' => 'dashDnDiag',
+ 'dashed_upward_diagonal' => 'dashUpDiag',
+ 'dashed_horizontal' => 'dashHorz',
+ 'dashed_vertical' => 'dashVert',
+ 'small_confetti' => 'smConfetti',
+ 'large_confetti' => 'lgConfetti',
- 'zigzag' => 'zigZag',
- 'wave' => 'wave',
- 'diagonal_brick' => 'diagBrick',
- 'horizontal_brick' => 'horzBrick',
- 'weave' => 'weave',
- 'plaid' => 'plaid',
+ 'zigzag' => 'zigZag',
+ 'wave' => 'wave',
+ 'diagonal_brick' => 'diagBrick',
+ 'horizontal_brick' => 'horzBrick',
+ 'weave' => 'weave',
+ 'plaid' => 'plaid',
- 'divot' => 'divot',
- 'dotted_grid' => 'dotGrid',
- 'dotted_diamond' => 'dotDmnd',
- 'shingle' => 'shingle',
- 'trellis' => 'trellis',
- 'sphere' => 'sphere',
+ 'divot' => 'divot',
+ 'dotted_grid' => 'dotGrid',
+ 'dotted_diamond' => 'dotDmnd',
+ 'shingle' => 'shingle',
+ 'trellis' => 'trellis',
+ 'sphere' => 'sphere',
- 'small_grid' => 'smGrid',
- 'large_grid' => 'lgGrid',
- 'small_check' => 'smCheck',
- 'large_check' => 'lgCheck',
- 'outlined_diamond' => 'openDmnd',
- 'solid_diamond' => 'solidDmnd'
+ 'small_grid' => 'smGrid',
+ 'large_grid' => 'lgGrid',
+ 'small_check' => 'smCheck',
+ 'large_check' => 'lgCheck',
+ 'outlined_diamond' => 'openDmnd',
+ 'solid_diamond' => 'solidDmnd'
}
# Check for valid types.
if types[args[:pattern]]
pattern[:pattern] = types[args[:pattern]]
@@ -690,10 +683,11 @@
pattern
end
def line_fill_properties(params)
return { :_defined => 0 } unless params
+
ret = params.dup
ret[:dash_type] = yield if block_given? && ret[:dash_type]
ret[:_defined] = 1
ret
end
@@ -714,10 +708,11 @@
}
end
def value_or_raise(hash, key, msg)
raise "Unknown #{msg} '#{key}'" if hash[key.to_sym].nil?
+
hash[key.to_sym]
end
def palette_color(index)
# Adjust the colour index.
@@ -733,18 +728,18 @@
def process_workbook_options(*params)
case params.size
when 0
[{}, {}]
when 1 # one hash
- options_keys = [:tempdir, :date_1904, :optimization, :excel2003_style, :strings_to_urls]
+ options_keys = %i[tempdir date_1904 optimization excel2003_style strings_to_urls]
hash = params.first
- options = hash.reject{|k,v| !options_keys.include?(k)}
+ options = hash.reject { |k, _v| !options_keys.include?(k) }
default_format_properties =
hash[:default_format_properties] ||
- hash.reject{|k,v| options_keys.include?(k)}
+ hash.reject { |k, _v| options_keys.include?(k) }
[options, default_format_properties.dup]
when 2 # array which includes options and default_format_properties
options, default_format_properties = params
default_format_properties ||= {}
@@ -756,19 +751,18 @@
#
# Convert user defined font values into private hash values.
#
def convert_font_args(params)
return unless params
+
font = params_to_font(params)
# Convert font size units.
font[:_size] *= 100 if font[:_size] && font[:_size] != 0
# Convert rotation into 60,000ths of a degree.
- if ptrue?(font[:_rotation])
- font[:_rotation] = 60_000 * font[:_rotation].to_i
- end
+ font[:_rotation] = 60_000 * font[:_rotation].to_i if ptrue?(font[:_rotation])
font
end
def params_to_font(params)
@@ -789,13 +783,11 @@
#
# Write the <c:txPr> element.
#
def write_tx_pr(font, is_y_axis = nil) # :nodoc:
rotation = nil
- if font && font.respond_to?(:[]) && font[:_rotation]
- rotation = font[:_rotation]
- end
+ rotation = font[:_rotation] if font && font.respond_to?(:[]) && font[:_rotation]
@writer.tag_elements('c:txPr') do
# Write the a:bodyPr element.
write_a_body_pr(rotation, is_y_axis)
# Write the a:lstStyle element.
write_a_lst_style
@@ -812,18 +804,18 @@
attributes = []
if rot
if rot == 16_200_000
# 270 deg/stacked angle.
attributes << ['rot', 0]
- attributes << ['vert', 'wordArtVert']
+ attributes << %w[vert wordArtVert]
elsif rot == 16_260_000
# 271 deg/stacked angle.
attributes << ['rot', 0]
- attributes << ['vert', 'eaVert']
+ attributes << %w[vert eaVert]
else
attributes << ['rot', rot]
- attributes << ['vert', 'horz']
+ attributes << %w[vert horz]
end
end
@writer.empty_tag('a:bodyPr', attributes)
end
@@ -869,16 +861,12 @@
latin_attributes = get_font_latin_attributes(font)
has_color = ptrue?(font) && ptrue?(font[:_color])
if !latin_attributes.empty? || has_color
@writer.tag_elements(tag, style_attributes) do
- if has_color
- write_a_solid_fill(:color => font[:_color])
- end
- if !latin_attributes.empty?
- write_a_latin(latin_attributes)
- end
+ write_a_solid_fill(:color => font[:_color]) if has_color
+ write_a_latin(latin_attributes) unless latin_attributes.empty?
end
else
@writer.empty_tag(tag, style_attributes)
end
end
@@ -913,11 +901,11 @@
#
# Write the <a:srgbClr> element.
#
def write_a_srgb_clr(color, transparency = nil) # :nodoc:
tag = 'a:srgbClr'
- attributes = [ ['val', color] ]
+ attributes = [['val', color]]
if ptrue?(transparency)
@writer.tag_elements(tag, attributes) do
write_a_alpha(transparency)
end
@@ -934,10 +922,11 @@
# Convert a HTML style #RRGGBB color.
color_code.sub(/^#/, '').upcase
else
index = Format.color(color_code)
raise "Unknown color '#{color_code}' used in chart formatting." unless index
+
palette_color(index)
end
end
#
@@ -949,23 +938,21 @@
attributes = []
attributes << ['sz', font[:_size]] if ptrue?(font[:_size])
attributes << ['b', font[:_bold]] if font[:_bold]
attributes << ['i', font[:_italic]] if font[:_italic]
- attributes << ['u', 'sng'] if font[:_underline]
+ attributes << %w[u sng] if font[:_underline]
# Turn off baseline when testing fonts that don't have it.
- if font[:_baseline] != -1
- attributes << ['baseline', font[:_baseline]]
- end
+ attributes << ['baseline', font[:_baseline]] if font[:_baseline] != -1
attributes
end
#
# Write the <a:endParaRPr> element.
#
def write_a_end_para_rpr # :nodoc:
- @writer.empty_tag('a:endParaRPr', [ ['lang', 'en-US'] ])
+ @writer.empty_tag('a:endParaRPr', [%w[lang en-US]])
end
end
module WriteDPtPoint
#