caxlsx 3.4.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -1
- data/README.md +9 -11
- data/Rakefile +7 -5
- data/lib/axlsx/content_type/abstract_content_type.rb +9 -4
- data/lib/axlsx/content_type/content_type.rb +7 -5
- data/lib/axlsx/content_type/default.rb +4 -2
- data/lib/axlsx/content_type/override.rb +4 -2
- data/lib/axlsx/doc_props/app.rb +26 -24
- data/lib/axlsx/doc_props/core.rb +8 -6
- data/lib/axlsx/drawing/area_chart.rb +10 -8
- data/lib/axlsx/drawing/area_series.rb +12 -10
- data/lib/axlsx/drawing/ax_data_source.rb +2 -0
- data/lib/axlsx/drawing/axes.rb +6 -4
- data/lib/axlsx/drawing/axis.rb +21 -19
- data/lib/axlsx/drawing/bar_3D_chart.rb +14 -12
- data/lib/axlsx/drawing/bar_chart.rb +13 -11
- data/lib/axlsx/drawing/bar_series.rb +8 -6
- data/lib/axlsx/drawing/bubble_chart.rb +6 -4
- data/lib/axlsx/drawing/bubble_series.rb +8 -6
- data/lib/axlsx/drawing/cat_axis.rb +12 -10
- data/lib/axlsx/drawing/chart.rb +20 -18
- data/lib/axlsx/drawing/d_lbls.rb +7 -5
- data/lib/axlsx/drawing/drawing.rb +58 -56
- data/lib/axlsx/drawing/graphic_frame.rb +6 -4
- data/lib/axlsx/drawing/hyperlink.rb +10 -8
- data/lib/axlsx/drawing/line_3D_chart.rb +7 -5
- data/lib/axlsx/drawing/line_chart.rb +10 -8
- data/lib/axlsx/drawing/line_series.rb +12 -10
- data/lib/axlsx/drawing/marker.rb +9 -7
- data/lib/axlsx/drawing/num_data.rb +9 -7
- data/lib/axlsx/drawing/num_data_source.rb +9 -7
- data/lib/axlsx/drawing/num_val.rb +7 -5
- data/lib/axlsx/drawing/one_cell_anchor.rb +7 -5
- data/lib/axlsx/drawing/pic.rb +16 -14
- data/lib/axlsx/drawing/picture_locking.rb +3 -1
- data/lib/axlsx/drawing/pie_3D_chart.rb +5 -3
- data/lib/axlsx/drawing/pie_series.rb +8 -6
- data/lib/axlsx/drawing/scaling.rb +8 -6
- data/lib/axlsx/drawing/scatter_chart.rb +7 -5
- data/lib/axlsx/drawing/scatter_series.rb +14 -12
- data/lib/axlsx/drawing/ser_axis.rb +7 -5
- data/lib/axlsx/drawing/series.rb +6 -4
- data/lib/axlsx/drawing/series_title.rb +6 -4
- data/lib/axlsx/drawing/str_data.rb +7 -5
- data/lib/axlsx/drawing/str_val.rb +6 -4
- data/lib/axlsx/drawing/title.rb +13 -14
- data/lib/axlsx/drawing/two_cell_anchor.rb +4 -2
- data/lib/axlsx/drawing/val_axis.rb +4 -2
- data/lib/axlsx/drawing/view_3D.rb +9 -7
- data/lib/axlsx/drawing/vml_drawing.rb +18 -16
- data/lib/axlsx/drawing/vml_shape.rb +24 -22
- data/lib/axlsx/package.rb +69 -66
- data/lib/axlsx/rels/relationship.rb +10 -5
- data/lib/axlsx/rels/relationships.rb +5 -3
- data/lib/axlsx/stylesheet/border.rb +6 -4
- data/lib/axlsx/stylesheet/border_pr.rb +5 -3
- data/lib/axlsx/stylesheet/cell_alignment.rb +12 -10
- data/lib/axlsx/stylesheet/cell_protection.rb +5 -3
- data/lib/axlsx/stylesheet/cell_style.rb +10 -8
- data/lib/axlsx/stylesheet/color.rb +9 -7
- data/lib/axlsx/stylesheet/dxf.rb +5 -3
- data/lib/axlsx/stylesheet/fill.rb +3 -1
- data/lib/axlsx/stylesheet/font.rb +18 -16
- data/lib/axlsx/stylesheet/gradient_fill.rb +6 -4
- data/lib/axlsx/stylesheet/gradient_stop.rb +6 -4
- data/lib/axlsx/stylesheet/num_fmt.rb +8 -10
- data/lib/axlsx/stylesheet/pattern_fill.rb +5 -3
- data/lib/axlsx/stylesheet/styles.rb +69 -71
- data/lib/axlsx/stylesheet/table_style.rb +7 -5
- data/lib/axlsx/stylesheet/table_style_element.rb +6 -4
- data/lib/axlsx/stylesheet/table_styles.rb +6 -4
- data/lib/axlsx/stylesheet/xf.rb +18 -16
- data/lib/axlsx/util/accessors.rb +4 -2
- data/lib/axlsx/util/buffered_zip_output_stream.rb +60 -0
- data/lib/axlsx/util/constants.rb +117 -104
- data/lib/axlsx/util/mime_type_utils.rb +3 -5
- data/lib/axlsx/util/options_parser.rb +3 -1
- data/lib/axlsx/util/serialized_attributes.rb +42 -17
- data/lib/axlsx/util/simple_typed_list.rb +47 -47
- data/lib/axlsx/util/storage.rb +11 -10
- data/lib/axlsx/util/validators.rb +101 -41
- data/lib/axlsx/util/zip_command.rb +10 -10
- data/lib/axlsx/version.rb +3 -1
- data/lib/axlsx/workbook/defined_name.rb +6 -4
- data/lib/axlsx/workbook/defined_names.rb +3 -1
- data/lib/axlsx/workbook/shared_strings_table.rb +8 -6
- data/lib/axlsx/workbook/workbook.rb +78 -76
- data/lib/axlsx/workbook/workbook_view.rb +3 -1
- data/lib/axlsx/workbook/workbook_views.rb +3 -1
- data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +65 -8
- data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +7 -3
- data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +11 -7
- data/lib/axlsx/workbook/worksheet/auto_filter/sort_condition.rb +51 -0
- data/lib/axlsx/workbook/worksheet/auto_filter/sort_state.rb +56 -0
- data/lib/axlsx/workbook/worksheet/border_creator.rb +5 -3
- data/lib/axlsx/workbook/worksheet/break.rb +3 -1
- data/lib/axlsx/workbook/worksheet/cell.rb +53 -54
- data/lib/axlsx/workbook/worksheet/cell_serializer.rb +31 -27
- data/lib/axlsx/workbook/worksheet/cfvo.rb +5 -3
- data/lib/axlsx/workbook/worksheet/cfvos.rb +3 -1
- data/lib/axlsx/workbook/worksheet/col.rb +5 -3
- data/lib/axlsx/workbook/worksheet/col_breaks.rb +5 -3
- data/lib/axlsx/workbook/worksheet/color_scale.rb +12 -10
- data/lib/axlsx/workbook/worksheet/cols.rb +3 -1
- data/lib/axlsx/workbook/worksheet/comment.rb +8 -6
- data/lib/axlsx/workbook/worksheet/comments.rb +6 -4
- data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +9 -4
- data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +18 -16
- data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +3 -1
- data/lib/axlsx/workbook/worksheet/data_bar.rb +14 -13
- data/lib/axlsx/workbook/worksheet/data_validation.rb +30 -28
- data/lib/axlsx/workbook/worksheet/data_validations.rb +3 -1
- data/lib/axlsx/workbook/worksheet/date_time_converter.rb +7 -5
- data/lib/axlsx/workbook/worksheet/dimension.rb +4 -2
- data/lib/axlsx/workbook/worksheet/header_footer.rb +4 -2
- data/lib/axlsx/workbook/worksheet/icon_set.rb +23 -6
- data/lib/axlsx/workbook/worksheet/merged_cells.rb +5 -5
- data/lib/axlsx/workbook/worksheet/outline_pr.rb +6 -2
- data/lib/axlsx/workbook/worksheet/page_margins.rb +15 -10
- data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +6 -2
- data/lib/axlsx/workbook/worksheet/page_setup.rb +11 -9
- data/lib/axlsx/workbook/worksheet/pane.rb +11 -9
- data/lib/axlsx/workbook/worksheet/pivot_table.rb +20 -19
- data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +8 -6
- data/lib/axlsx/workbook/worksheet/pivot_tables.rb +2 -0
- data/lib/axlsx/workbook/worksheet/print_options.rb +3 -1
- data/lib/axlsx/workbook/worksheet/protected_range.rb +3 -1
- data/lib/axlsx/workbook/worksheet/protected_ranges.rb +5 -3
- data/lib/axlsx/workbook/worksheet/rich_text.rb +3 -1
- data/lib/axlsx/workbook/worksheet/rich_text_run.rb +16 -14
- data/lib/axlsx/workbook/worksheet/row.rb +6 -7
- data/lib/axlsx/workbook/worksheet/row_breaks.rb +6 -4
- data/lib/axlsx/workbook/worksheet/selection.rb +9 -7
- data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +6 -2
- data/lib/axlsx/workbook/worksheet/sheet_data.rb +3 -1
- data/lib/axlsx/workbook/worksheet/sheet_format_pr.rb +6 -2
- data/lib/axlsx/workbook/worksheet/sheet_pr.rb +8 -4
- data/lib/axlsx/workbook/worksheet/sheet_protection.rb +10 -8
- data/lib/axlsx/workbook/worksheet/sheet_view.rb +15 -13
- data/lib/axlsx/workbook/worksheet/table.rb +9 -7
- data/lib/axlsx/workbook/worksheet/table_style_info.rb +4 -2
- data/lib/axlsx/workbook/worksheet/tables.rb +3 -1
- data/lib/axlsx/workbook/worksheet/worksheet.rb +38 -37
- data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +4 -2
- data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +8 -2
- data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +6 -4
- data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +4 -2
- data/lib/axlsx.rb +56 -42
- data/lib/caxlsx.rb +3 -1
- metadata +49 -43
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Axlsx
|
4
|
+
# This class represents a individual sort condition belonging to the sort state of an auto filter
|
5
|
+
class SortCondition
|
6
|
+
# Creates a new SortCondition object
|
7
|
+
# @param [Integer] column_index Zero-based index indicating the AutoFilter column to which the sorting should be applied to
|
8
|
+
# @param [Symbol] order The order the column should be sorted on, can only be :asc or :desc
|
9
|
+
# @param [Array] custom_list An array containg a custom sorting list in order.
|
10
|
+
def initialize(column_index:, order:, custom_list:)
|
11
|
+
Axlsx.validate_int column_index
|
12
|
+
@column_index = column_index
|
13
|
+
|
14
|
+
RestrictionValidator.validate 'SortCondition.order', [:asc, :desc], order
|
15
|
+
@order = order
|
16
|
+
|
17
|
+
DataTypeValidator.validate :sort_condition_custom_list, Array, custom_list
|
18
|
+
@custom_list = custom_list
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :column_index, :order, :custom_list
|
22
|
+
|
23
|
+
# converts the ref String from the sort_state to a string representing the ref of a single column
|
24
|
+
# for the xml string to be returned.
|
25
|
+
def ref_to_single_column(ref, column_index)
|
26
|
+
first_cell, last_cell = ref.split(':')
|
27
|
+
|
28
|
+
start_point = Axlsx.name_to_indices(first_cell)
|
29
|
+
|
30
|
+
first_row = first_cell[/\d+/]
|
31
|
+
last_row = last_cell[/\d+/]
|
32
|
+
|
33
|
+
first_column = Axlsx.col_ref(column_index + start_point.first)
|
34
|
+
last_column = first_column
|
35
|
+
|
36
|
+
"#{first_column}#{first_row}:#{last_column}#{last_row}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# serialize the object
|
40
|
+
# @return [String]
|
41
|
+
def to_xml_string(str, ref)
|
42
|
+
ref = ref_to_single_column(ref, column_index)
|
43
|
+
|
44
|
+
str << "<sortCondition "
|
45
|
+
str << "descending='1' " if order == :desc
|
46
|
+
str << "ref='#{ref}' "
|
47
|
+
str << "customList='#{custom_list.join(',')}' " unless custom_list.empty?
|
48
|
+
str << "/>"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'axlsx/workbook/worksheet/auto_filter/sort_condition'
|
4
|
+
|
5
|
+
module Axlsx
|
6
|
+
# This class performs sorting on a range in a worksheet
|
7
|
+
class SortState
|
8
|
+
# creates a new SortState object
|
9
|
+
# @param [AutoFilter] auto_filter the auto_filter that this sort_state belongs to
|
10
|
+
def initialize(auto_filter)
|
11
|
+
@auto_filter = auto_filter
|
12
|
+
end
|
13
|
+
|
14
|
+
# A collection of SortConditions for this sort_state
|
15
|
+
# @return [SimpleTypedList]
|
16
|
+
def sort_conditions
|
17
|
+
@sort_conditions ||= SimpleTypedList.new SortCondition
|
18
|
+
end
|
19
|
+
|
20
|
+
# Adds a SortCondition to the sort_state. This is the recommended way to add conditions to it.
|
21
|
+
# It requires a column_index for the sorting, descending and the custom order are optional.
|
22
|
+
# @param [Integer] column_index Zero-based index indicating the AutoFilter column to which the sorting should be applied to
|
23
|
+
# @param [Symbol] order The order the column should be sorted on, can only be :asc or :desc
|
24
|
+
# @param [Array] custom_list An array containg a custom sorting list in order.
|
25
|
+
# @return [SortCondition]
|
26
|
+
def add_sort_condition(column_index:, order: :asc, custom_list: [])
|
27
|
+
sort_conditions << SortCondition.new(column_index: column_index, order: order, custom_list: custom_list)
|
28
|
+
sort_conditions.last
|
29
|
+
end
|
30
|
+
|
31
|
+
# method to increment the String representing the first cell of the range of the autofilter by 1 row for the sortCondition
|
32
|
+
# xml string
|
33
|
+
def increment_cell_value(str)
|
34
|
+
letter = str[/[A-Za-z]+/]
|
35
|
+
number = str[/\d+/].to_i
|
36
|
+
|
37
|
+
incremented_number = number + 1
|
38
|
+
|
39
|
+
"#{letter}#{incremented_number}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# serialize the object
|
43
|
+
# @return [String]
|
44
|
+
def to_xml_string(str = +'')
|
45
|
+
return if sort_conditions.empty?
|
46
|
+
|
47
|
+
ref = @auto_filter.range
|
48
|
+
first_cell, last_cell = ref.split(':')
|
49
|
+
ref = "#{increment_cell_value(first_cell)}:#{last_cell}"
|
50
|
+
|
51
|
+
str << "<sortState xmlns:xlrd2='http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2' ref='#{ref}'>"
|
52
|
+
sort_conditions.each { |sort_condition| sort_condition.to_xml_string(str, ref) }
|
53
|
+
str << "</sortState>"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
class BorderCreator
|
3
5
|
def initialize(worksheet:, cells:, edges: nil, style: nil, color: nil)
|
@@ -11,12 +13,12 @@ module Axlsx
|
|
11
13
|
if @edges == :all
|
12
14
|
@edges = Axlsx::Border::EDGES
|
13
15
|
elsif !@edges.is_a?(Array)
|
14
|
-
raise ArgumentError
|
16
|
+
raise ArgumentError, "Invalid edges provided, #{@edges}"
|
15
17
|
else
|
16
18
|
@edges = @edges.map { |x| x&.to_sym }.uniq
|
17
19
|
|
18
|
-
|
19
|
-
raise ArgumentError
|
20
|
+
unless (@edges - Axlsx::Border::EDGES).empty?
|
21
|
+
raise ArgumentError, "Invalid edges provided, #{edges}"
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# The Break class stores the details for row and column page breaks.
|
3
5
|
# @see RowBreaks, ColBreaks
|
@@ -25,7 +27,7 @@ module Axlsx
|
|
25
27
|
serializable_attributes :id, :min, :max, :man, :pt
|
26
28
|
|
27
29
|
# serializes the break to xml
|
28
|
-
def to_xml_string(str = '')
|
30
|
+
def to_xml_string(str = +'')
|
29
31
|
serialized_tag('brk', str)
|
30
32
|
end
|
31
33
|
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Axlsx
|
3
4
|
# A cell in a worksheet.
|
4
5
|
# Cell stores inforamation requried to serialize a single worksheet cell to xml. You must provde the Row that the cell belongs to and the cells value. The data type will automatically be determed if you do not specify the :type option. The default style will be applied if you do not supply the :style option. Changing the cell's type will recast the value to the type specified. Altering the cell's value via the property accessor will also automatically cast the provided value to the cell's type.
|
@@ -40,12 +41,13 @@ module Axlsx
|
|
40
41
|
self.type = type unless type == :string
|
41
42
|
|
42
43
|
val = options.delete(:style)
|
43
|
-
self.style = val unless val.nil? || val
|
44
|
+
self.style = val unless val.nil? || val.zero?
|
44
45
|
val = options.delete(:formula_value)
|
45
46
|
self.formula_value = val unless val.nil?
|
47
|
+
val = options.delete(:escape_formulas)
|
48
|
+
self.escape_formulas = val unless val.nil?
|
46
49
|
|
47
|
-
parse_options(options)
|
48
|
-
self.escape_formulas = row.worksheet.escape_formulas if escape_formulas.nil?
|
50
|
+
parse_options(options) unless options.empty?
|
49
51
|
|
50
52
|
self.value = value
|
51
53
|
value.cell = self if contains_rich_text?
|
@@ -70,15 +72,8 @@ module Axlsx
|
|
70
72
|
CELL_TYPES = [:date, :time, :float, :integer, :richtext,
|
71
73
|
:string, :boolean, :iso_8601, :text].freeze
|
72
74
|
|
73
|
-
#
|
74
|
-
|
75
|
-
FORMULA_PREFIXES = ['='.freeze].freeze
|
76
|
-
|
77
|
-
# Leading characters that indicate an array formula.
|
78
|
-
ARRAY_FORMULA_PREFIXES = ['{='.freeze].freeze
|
79
|
-
|
80
|
-
# Trailing character that indicates an array formula.
|
81
|
-
ARRAY_FORMULA_SUFFIX = '}'.freeze
|
75
|
+
# A regular expression to match the alpha(column)numeric(row) reference of a cell
|
76
|
+
CELL_REFERENCE_REGEX = /([A-Z]+)([0-9]+)/.freeze
|
82
77
|
|
83
78
|
# The index of the cellXfs item to be applied to this cell.
|
84
79
|
# @return [Integer]
|
@@ -87,10 +82,15 @@ module Axlsx
|
|
87
82
|
defined?(@style) ? @style : 0
|
88
83
|
end
|
89
84
|
|
85
|
+
# Internal
|
86
|
+
def style_str
|
87
|
+
defined?(@style) ? @style.to_s : '0'
|
88
|
+
end
|
89
|
+
|
90
90
|
attr_accessor :raw_style
|
91
91
|
|
92
92
|
# The index of the cellXfs item to be applied to this cell.
|
93
|
-
# @param [Hash]
|
93
|
+
# @param [Hash] style
|
94
94
|
# @see Axlsx::Styles
|
95
95
|
def add_style(style)
|
96
96
|
self.raw_style ||= {}
|
@@ -122,7 +122,7 @@ module Axlsx
|
|
122
122
|
# automatically determed.
|
123
123
|
# @see Cell#cell_type_from_value
|
124
124
|
# @return [Symbol] The type of data this cell's value is cast to.
|
125
|
-
# @raise [
|
125
|
+
# @raise [ArgumentError] Cell.type must be one of [:date, time, :float, :integer, :string, :boolean]
|
126
126
|
# @note
|
127
127
|
# If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
|
128
128
|
# :string to :integer or :float, type conversions always return 0 or 0.0
|
@@ -143,7 +143,9 @@ module Axlsx
|
|
143
143
|
# Allowing user-generated data to be interpreted as formulas is a security risk.
|
144
144
|
# See https://www.owasp.org/index.php/CSV_Injection for details.
|
145
145
|
# @return [Boolean]
|
146
|
-
|
146
|
+
def escape_formulas
|
147
|
+
defined?(@escape_formulas) ? @escape_formulas : row.worksheet.escape_formulas
|
148
|
+
end
|
147
149
|
|
148
150
|
# Sets whether to treat values starting with an equals sign as formulas or as literal strings.
|
149
151
|
# @param [Boolean] value The value to set.
|
@@ -164,7 +166,7 @@ module Axlsx
|
|
164
166
|
|
165
167
|
# Indicates that the cell has one or more of the custom cell styles applied.
|
166
168
|
# @return [Boolean]
|
167
|
-
def is_text_run?
|
169
|
+
def is_text_run? # rubocop:disable Naming/PredicateName
|
168
170
|
defined?(@is_text_run) && @is_text_run && !contains_rich_text?
|
169
171
|
end
|
170
172
|
|
@@ -174,12 +176,12 @@ module Axlsx
|
|
174
176
|
|
175
177
|
# Indicates if the cell is good for shared string table
|
176
178
|
def plain_string?
|
177
|
-
(type == :string || type == :text) &&
|
178
|
-
!
|
179
|
-
|
180
|
-
|
181
|
-
!is_formula? &&
|
182
|
-
!is_array_formula?
|
179
|
+
(type == :string || type == :text) && # String typed
|
180
|
+
!value.nil? &&
|
181
|
+
!value.empty? &&
|
182
|
+
!is_text_run? && # No inline styles
|
183
|
+
!is_formula? &&
|
184
|
+
!is_array_formula?
|
183
185
|
end
|
184
186
|
|
185
187
|
# The inline font_name property for the cell
|
@@ -280,15 +282,13 @@ module Axlsx
|
|
280
282
|
def extend=(v) set_run_style :validate_boolean, :extend, v; end
|
281
283
|
|
282
284
|
# The inline underline property for the cell.
|
283
|
-
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
285
|
+
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
284
286
|
# @return [Boolean]
|
285
287
|
# @return [String]
|
286
|
-
# @note true is for backwards compatability and is reassigned to :single
|
287
288
|
attr_reader :u
|
288
289
|
|
289
290
|
# @see u
|
290
291
|
def u=(v)
|
291
|
-
v = :single if (v == true || v == 1 || v == :true || v == 'true')
|
292
292
|
set_run_style :validate_cell_u, :u, v
|
293
293
|
end
|
294
294
|
|
@@ -298,7 +298,7 @@ module Axlsx
|
|
298
298
|
|
299
299
|
# @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
|
300
300
|
def color=(v)
|
301
|
-
@color = v.is_a?(Color) ? v : Color.new(:
|
301
|
+
@color = v.is_a?(Color) ? v : Color.new(rgb: v)
|
302
302
|
@is_text_run = true
|
303
303
|
end
|
304
304
|
|
@@ -344,20 +344,20 @@ module Axlsx
|
|
344
344
|
# @example Relative Cell Reference
|
345
345
|
# ws.rows.first.cells.first.r #=> "A1"
|
346
346
|
def r
|
347
|
-
Axlsx
|
347
|
+
Axlsx.cell_r index, @row.row_index
|
348
348
|
end
|
349
349
|
|
350
|
-
# @return [String] The absolute alpha(column)numeric(row) reference for this
|
350
|
+
# @return [String] The absolute alpha(column)numeric(row) reference for this cell.
|
351
351
|
# @example Absolute Cell Reference
|
352
352
|
# ws.rows.first.cells.first.r #=> "$A$1"
|
353
353
|
def r_abs
|
354
|
-
"$#{
|
354
|
+
"$#{CELL_REFERENCE_REGEX.match(r)[1, 2].join('$')}"
|
355
355
|
end
|
356
356
|
|
357
357
|
# @return [Integer] The cellXfs item index applied to this cell.
|
358
358
|
# @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
|
359
359
|
def style=(v)
|
360
|
-
Axlsx
|
360
|
+
Axlsx.validate_unsigned_int(v)
|
361
361
|
count = styles.cellXfs.size
|
362
362
|
raise ArgumentError, "Invalid cellXfs id" unless v < count
|
363
363
|
|
@@ -374,11 +374,11 @@ module Axlsx
|
|
374
374
|
# @param [Cell, String] target The last cell, or str ref for the cell in the merge range
|
375
375
|
def merge(target)
|
376
376
|
start, stop = if target.is_a?(String)
|
377
|
-
[
|
377
|
+
[r, target]
|
378
378
|
elsif target.is_a?(Cell)
|
379
|
-
Axlsx.sort_cells([self, target]).map
|
379
|
+
Axlsx.sort_cells([self, target]).map(&:r)
|
380
380
|
end
|
381
|
-
|
381
|
+
row.worksheet.merge_cells "#{start}:#{stop}" unless stop.nil?
|
382
382
|
end
|
383
383
|
|
384
384
|
# Serializes the cell
|
@@ -386,21 +386,21 @@ module Axlsx
|
|
386
386
|
# @param [Integer] c_index The cell index in the row.
|
387
387
|
# @param [String] str The string index the cell content will be appended to. Defaults to empty string.
|
388
388
|
# @return [String] xml text for the cell
|
389
|
-
def to_xml_string(r_index, c_index, str = '')
|
389
|
+
def to_xml_string(r_index, c_index, str = +'')
|
390
390
|
CellSerializer.to_xml_string r_index, c_index, self, str
|
391
391
|
end
|
392
392
|
|
393
|
-
def is_formula?
|
393
|
+
def is_formula? # rubocop:disable Naming/PredicateName
|
394
394
|
return false if escape_formulas
|
395
395
|
|
396
|
-
type == :string && @value.to_s.start_with?(
|
396
|
+
type == :string && @value.to_s.start_with?(FORMULA_PREFIX)
|
397
397
|
end
|
398
398
|
|
399
|
-
def is_array_formula?
|
399
|
+
def is_array_formula? # rubocop:disable Naming/PredicateName
|
400
400
|
return false if escape_formulas
|
401
401
|
|
402
402
|
type == :string &&
|
403
|
-
@value.to_s.start_with?(
|
403
|
+
@value.to_s.start_with?(ARRAY_FORMULA_PREFIX) &&
|
404
404
|
@value.to_s.end_with?(ARRAY_FORMULA_SUFFIX)
|
405
405
|
end
|
406
406
|
|
@@ -425,7 +425,7 @@ module Axlsx
|
|
425
425
|
# Attempts to determine the correct width for this cell's content
|
426
426
|
# @return [Float]
|
427
427
|
def autowidth
|
428
|
-
return if
|
428
|
+
return if value.nil? || is_formula?
|
429
429
|
|
430
430
|
if contains_rich_text?
|
431
431
|
string_width('', font_size) + value.autowidth
|
@@ -441,12 +441,13 @@ module Axlsx
|
|
441
441
|
end
|
442
442
|
end
|
443
443
|
|
444
|
-
# Returns the
|
445
|
-
# TODO find a better way to do this as it accounts for 30% of
|
444
|
+
# Returns the sanitized value
|
445
|
+
# TODO: find a better way to do this as it accounts for 30% of
|
446
446
|
# processing time in benchmarking...
|
447
|
+
# @return [String] The sanitized value
|
447
448
|
def clean_value
|
448
|
-
if (type == :string || type == :text) && !Axlsx
|
449
|
-
Axlsx
|
449
|
+
if (type == :string || type == :text) && !Axlsx.trust_input
|
450
|
+
Axlsx.sanitize(::CGI.escapeHTML(@value.to_s))
|
450
451
|
else
|
451
452
|
@value.to_s
|
452
453
|
end
|
@@ -481,13 +482,13 @@ module Axlsx
|
|
481
482
|
return unless INLINE_STYLES.include?(attr.to_sym)
|
482
483
|
|
483
484
|
Axlsx.send(validator, value) unless validator.nil?
|
484
|
-
|
485
|
+
instance_variable_set :"@#{attr}", value
|
485
486
|
@is_text_run = true
|
486
487
|
end
|
487
488
|
|
488
489
|
# @see ssti
|
489
490
|
def ssti=(v)
|
490
|
-
Axlsx
|
491
|
+
Axlsx.validate_unsigned_int(v)
|
491
492
|
@ssti = v
|
492
493
|
end
|
493
494
|
|
@@ -506,13 +507,11 @@ module Axlsx
|
|
506
507
|
:time
|
507
508
|
elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
508
509
|
:boolean
|
509
|
-
elsif v.
|
510
|
+
elsif v.respond_to?(:to_i) && Axlsx::NUMERIC_REGEX.match?(v.to_s)
|
510
511
|
:integer
|
511
|
-
elsif v.
|
512
|
-
:float
|
513
|
-
elsif (matchdata = v.to_s.match(MAYBE_FLOAT_REGEX)) && (Float::MIN_10_EXP..Float::MAX_10_EXP).cover?(matchdata[:exp].to_i) && v.respond_to?(:to_f)
|
512
|
+
elsif v.respond_to?(:to_f) && (Axlsx::SAFE_FLOAT_REGEX.match?(v.to_s) || ((matchdata = MAYBE_FLOAT_REGEX.match(v.to_s)) && matchdata[:exp].to_i.between?(Float::MIN_10_EXP, Float::MAX_10_EXP)))
|
514
513
|
:float
|
515
|
-
elsif v.to_s
|
514
|
+
elsif Axlsx::ISO_8601_REGEX.match?(v.to_s)
|
516
515
|
:iso_8601
|
517
516
|
elsif v.is_a? RichText
|
518
517
|
:richtext
|
@@ -526,18 +525,18 @@ module Axlsx
|
|
526
525
|
# About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values.
|
527
526
|
# @see Axlsx#date1904
|
528
527
|
def cast_value(v)
|
529
|
-
return v if v.
|
528
|
+
return v if v.nil? || v.is_a?(RichText)
|
530
529
|
|
531
530
|
case type
|
532
531
|
when :date
|
533
|
-
self.style = STYLE_DATE if
|
532
|
+
self.style = STYLE_DATE if style.zero?
|
534
533
|
if !v.is_a?(Date) && v.respond_to?(:to_date)
|
535
534
|
v.to_date
|
536
535
|
else
|
537
536
|
v
|
538
537
|
end
|
539
538
|
when :time
|
540
|
-
self.style = STYLE_DATE if
|
539
|
+
self.style = STYLE_DATE if style.zero?
|
541
540
|
if !v.is_a?(Time) && v.respond_to?(:to_time)
|
542
541
|
v.to_time
|
543
542
|
else
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# The Cell Serializer class contains the logic for serializing cells based on their type.
|
3
5
|
class CellSerializer
|
@@ -7,28 +9,30 @@ module Axlsx
|
|
7
9
|
# @param [Integer] column_index The index of the cell's column
|
8
10
|
# @param [String] str The string to apend serialization to.
|
9
11
|
# @return [String]
|
10
|
-
def to_xml_string(row_index, column_index, cell, str = '')
|
11
|
-
str <<
|
12
|
+
def to_xml_string(row_index, column_index, cell, str = +'')
|
13
|
+
str << '<c r="'
|
14
|
+
str << Axlsx.col_ref(column_index) << Axlsx.row_ref(row_index)
|
15
|
+
str << '" s="' << cell.style_str << '" '
|
12
16
|
return str << '/>' if cell.value.nil?
|
13
17
|
|
14
18
|
method = cell.type
|
15
|
-
|
19
|
+
send(method, cell, str)
|
16
20
|
str << '</c>'
|
17
21
|
end
|
18
22
|
|
19
23
|
# builds an xml text run based on this cells attributes.
|
20
24
|
# @param [String] str The string instance this run will be concated to.
|
21
25
|
# @return [String]
|
22
|
-
def run_xml_string(cell, str = '')
|
26
|
+
def run_xml_string(cell, str = +'')
|
23
27
|
if cell.is_text_run?
|
24
28
|
valid = RichTextRun::INLINE_STYLES - [:value, :type]
|
25
|
-
data =
|
26
|
-
data = data.select { |key, value| valid.include?(key)
|
29
|
+
data = Axlsx.instance_values_for(cell).transform_keys(&:to_sym)
|
30
|
+
data = data.select { |key, value| !value.nil? && valid.include?(key) }
|
27
31
|
RichText.new(cell.value.to_s, data).to_xml_string(str)
|
28
32
|
elsif cell.contains_rich_text?
|
29
33
|
cell.value.to_xml_string(str)
|
30
34
|
else
|
31
|
-
str <<
|
35
|
+
str << '<t>' << cell.clean_value << '</t>'
|
32
36
|
end
|
33
37
|
str
|
34
38
|
end
|
@@ -37,7 +41,7 @@ module Axlsx
|
|
37
41
|
# @param [Cell] cell The cell that is being serialized
|
38
42
|
# @param [String] str The string the serialized content will be appended to.
|
39
43
|
# @return [String]
|
40
|
-
def iso_8601(cell, str = '')
|
44
|
+
def iso_8601(cell, str = +'')
|
41
45
|
value_serialization 'd', cell.value, str
|
42
46
|
end
|
43
47
|
|
@@ -45,23 +49,23 @@ module Axlsx
|
|
45
49
|
# @param [Cell] cell The cell that is being serialized
|
46
50
|
# @param [String] str The string the serialized content will be appended to.
|
47
51
|
# @return [String]
|
48
|
-
def date(cell, str = '')
|
49
|
-
value_serialization false, DateTimeConverter
|
52
|
+
def date(cell, str = +'')
|
53
|
+
value_serialization false, DateTimeConverter.date_to_serial(cell.value).to_s, str
|
50
54
|
end
|
51
55
|
|
52
56
|
# Serializes cells that are type time
|
53
57
|
# @param [Cell] cell The cell that is being serialized
|
54
58
|
# @param [String] str The string the serialized content will be appended to.
|
55
59
|
# @return [String]
|
56
|
-
def time(cell, str = '')
|
57
|
-
value_serialization false, DateTimeConverter
|
60
|
+
def time(cell, str = +'')
|
61
|
+
value_serialization false, DateTimeConverter.time_to_serial(cell.value).to_s, str
|
58
62
|
end
|
59
63
|
|
60
64
|
# Serializes cells that are type boolean
|
61
65
|
# @param [Cell] cell The cell that is being serialized
|
62
66
|
# @param [String] str The string the serialized content will be appended to.
|
63
67
|
# @return [String]
|
64
|
-
def boolean(cell, str = '')
|
68
|
+
def boolean(cell, str = +'')
|
65
69
|
value_serialization 'b', cell.value.to_s, str
|
66
70
|
end
|
67
71
|
|
@@ -69,7 +73,7 @@ module Axlsx
|
|
69
73
|
# @param [Cell] cell The cell that is being serialized
|
70
74
|
# @param [String] str The string the serialized content will be appended to.
|
71
75
|
# @return [String]
|
72
|
-
def float(cell, str = '')
|
76
|
+
def float(cell, str = +'')
|
73
77
|
numeric cell, str
|
74
78
|
end
|
75
79
|
|
@@ -77,7 +81,7 @@ module Axlsx
|
|
77
81
|
# @param [Cell] cell The cell that is being serialized
|
78
82
|
# @param [String] str The string the serialized content will be appended to.
|
79
83
|
# @return [String]
|
80
|
-
def integer(cell, str = '')
|
84
|
+
def integer(cell, str = +'')
|
81
85
|
numeric cell, str
|
82
86
|
end
|
83
87
|
|
@@ -85,25 +89,25 @@ module Axlsx
|
|
85
89
|
# @param [Cell] cell The cell that is being serialized
|
86
90
|
# @param [String] str The string the serialized content will be appended to.
|
87
91
|
# @return [String]
|
88
|
-
def formula_serialization(cell, str = '')
|
89
|
-
str <<
|
90
|
-
str <<
|
92
|
+
def formula_serialization(cell, str = +'')
|
93
|
+
str << 't="str"><f>' << cell.clean_value.delete_prefix(FORMULA_PREFIX) << '</f>'
|
94
|
+
str << '<v>' << cell.formula_value.to_s << '</v>' unless cell.formula_value.nil?
|
91
95
|
end
|
92
96
|
|
93
97
|
# Serializes cells that are type array formula
|
94
98
|
# @param [Cell] cell The cell that is being serialized
|
95
99
|
# @param [String] str The string the serialized content will be appended to.
|
96
100
|
# @return [String]
|
97
|
-
def array_formula_serialization(cell, str = '')
|
98
|
-
str <<
|
99
|
-
str <<
|
101
|
+
def array_formula_serialization(cell, str = +'')
|
102
|
+
str << 't="str">' << '<f t="array" ref="' << cell.r << '">' << cell.clean_value.delete_prefix(ARRAY_FORMULA_PREFIX).delete_suffix(ARRAY_FORMULA_SUFFIX) << '</f>'
|
103
|
+
str << '<v>' << cell.formula_value.to_s << '</v>' unless cell.formula_value.nil?
|
100
104
|
end
|
101
105
|
|
102
106
|
# Serializes cells that are type inline_string
|
103
107
|
# @param [Cell] cell The cell that is being serialized
|
104
108
|
# @param [String] str The string the serialized content will be appended to.
|
105
109
|
# @return [String]
|
106
|
-
def inline_string_serialization(cell, str = '')
|
110
|
+
def inline_string_serialization(cell, str = +'')
|
107
111
|
str << 't="inlineStr"><is>'
|
108
112
|
run_xml_string cell, str
|
109
113
|
str << '</is>'
|
@@ -113,7 +117,7 @@ module Axlsx
|
|
113
117
|
# @param [Cell] cell The cell that is being serialized
|
114
118
|
# @param [String] str The string the serialized content will be appended to.
|
115
119
|
# @return [String]
|
116
|
-
def string(cell, str = '')
|
120
|
+
def string(cell, str = +'')
|
117
121
|
if cell.is_array_formula?
|
118
122
|
array_formula_serialization cell, str
|
119
123
|
elsif cell.is_formula?
|
@@ -151,13 +155,13 @@ module Axlsx
|
|
151
155
|
|
152
156
|
private
|
153
157
|
|
154
|
-
def numeric(cell, str = '')
|
158
|
+
def numeric(cell, str = +'')
|
155
159
|
value_serialization 'n', cell.value, str
|
156
160
|
end
|
157
161
|
|
158
|
-
def value_serialization(serialization_type, serialization_value, str = '')
|
159
|
-
str <<
|
160
|
-
str <<
|
162
|
+
def value_serialization(serialization_type, serialization_value, str = +'')
|
163
|
+
str << 't="' << serialization_type.to_s << '"' if serialization_type
|
164
|
+
str << '><v>' << serialization_value.to_s << '</v>'
|
161
165
|
end
|
162
166
|
end
|
163
167
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# Conditional Format Value Object
|
3
5
|
# Describes the values of the interpolation points in a gradient scale. This object is used by ColorScale, DataBar and IconSet classes
|
@@ -38,10 +40,10 @@ module Axlsx
|
|
38
40
|
attr_reader :val
|
39
41
|
|
40
42
|
# @see type
|
41
|
-
def type=(v); Axlsx
|
43
|
+
def type=(v); Axlsx.validate_conditional_formatting_value_object_type(v); @type = v end
|
42
44
|
|
43
45
|
# @see gte
|
44
|
-
def gte=(v); Axlsx
|
46
|
+
def gte=(v); Axlsx.validate_boolean(v); @gte = v end
|
45
47
|
|
46
48
|
# @see val
|
47
49
|
def val=(v)
|
@@ -53,7 +55,7 @@ module Axlsx
|
|
53
55
|
# serialize the Csvo object
|
54
56
|
# @param [String] str
|
55
57
|
# @return [String]
|
56
|
-
def to_xml_string(str = '')
|
58
|
+
def to_xml_string(str = +'')
|
57
59
|
serialized_tag('cfvo', str)
|
58
60
|
end
|
59
61
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# A collection of Cfvo objects that initializes with the required
|
3
5
|
# first two items
|
@@ -9,7 +11,7 @@ module Axlsx
|
|
9
11
|
# Serialize the Cfvo object
|
10
12
|
# @param [String] str
|
11
13
|
# @return [String]
|
12
|
-
def to_xml_string(str = '')
|
14
|
+
def to_xml_string(str = +'')
|
13
15
|
each { |cfvo| cfvo.to_xml_string(str) }
|
14
16
|
end
|
15
17
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# The Col class defines column attributes for columns in sheets.
|
3
5
|
class Col
|
@@ -86,7 +88,7 @@ module Axlsx
|
|
86
88
|
# @see Col#outline
|
87
89
|
def outline_level=(v)
|
88
90
|
Axlsx.validate_unsigned_numeric(v)
|
89
|
-
raise ArgumentError, 'outlineLevel must be between 0 and 7' unless
|
91
|
+
raise ArgumentError, 'outlineLevel must be between 0 and 7' unless v >= 0 && v <= 7
|
90
92
|
|
91
93
|
@outline_level = v
|
92
94
|
end
|
@@ -112,7 +114,7 @@ module Axlsx
|
|
112
114
|
# current @width value.
|
113
115
|
# TODO!!!
|
114
116
|
# Axlsx.validate_unsigned_numeric(v) unless v == nil
|
115
|
-
@custom_width = @best_fit = v
|
117
|
+
@custom_width = @best_fit = !v.nil?
|
116
118
|
@width = v.nil? ? v : [v, MAX_WIDTH].min
|
117
119
|
end
|
118
120
|
|
@@ -135,7 +137,7 @@ module Axlsx
|
|
135
137
|
# Serialize this columns data to an xml string
|
136
138
|
# @param [String] str
|
137
139
|
# @return [String]
|
138
|
-
def to_xml_string(str = '')
|
140
|
+
def to_xml_string(str = +'')
|
139
141
|
serialized_tag('col', str)
|
140
142
|
end
|
141
143
|
end
|