caxlsx 3.4.0 → 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 -0
- data/README.md +11 -12
- 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 +55 -48
- 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,9 +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 = ['-', '=', '+', '@', '%', '|', "\r", "\t"].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
|
76
77
|
|
77
78
|
# The index of the cellXfs item to be applied to this cell.
|
78
79
|
# @return [Integer]
|
@@ -81,10 +82,15 @@ module Axlsx
|
|
81
82
|
defined?(@style) ? @style : 0
|
82
83
|
end
|
83
84
|
|
85
|
+
# Internal
|
86
|
+
def style_str
|
87
|
+
defined?(@style) ? @style.to_s : '0'
|
88
|
+
end
|
89
|
+
|
84
90
|
attr_accessor :raw_style
|
85
91
|
|
86
92
|
# The index of the cellXfs item to be applied to this cell.
|
87
|
-
# @param [Hash]
|
93
|
+
# @param [Hash] style
|
88
94
|
# @see Axlsx::Styles
|
89
95
|
def add_style(style)
|
90
96
|
self.raw_style ||= {}
|
@@ -116,7 +122,7 @@ module Axlsx
|
|
116
122
|
# automatically determed.
|
117
123
|
# @see Cell#cell_type_from_value
|
118
124
|
# @return [Symbol] The type of data this cell's value is cast to.
|
119
|
-
# @raise [
|
125
|
+
# @raise [ArgumentError] Cell.type must be one of [:date, time, :float, :integer, :string, :boolean]
|
120
126
|
# @note
|
121
127
|
# If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
|
122
128
|
# :string to :integer or :float, type conversions always return 0 or 0.0
|
@@ -137,7 +143,9 @@ module Axlsx
|
|
137
143
|
# Allowing user-generated data to be interpreted as formulas is a security risk.
|
138
144
|
# See https://www.owasp.org/index.php/CSV_Injection for details.
|
139
145
|
# @return [Boolean]
|
140
|
-
|
146
|
+
def escape_formulas
|
147
|
+
defined?(@escape_formulas) ? @escape_formulas : row.worksheet.escape_formulas
|
148
|
+
end
|
141
149
|
|
142
150
|
# Sets whether to treat values starting with an equals sign as formulas or as literal strings.
|
143
151
|
# @param [Boolean] value The value to set.
|
@@ -158,7 +166,7 @@ module Axlsx
|
|
158
166
|
|
159
167
|
# Indicates that the cell has one or more of the custom cell styles applied.
|
160
168
|
# @return [Boolean]
|
161
|
-
def is_text_run?
|
169
|
+
def is_text_run? # rubocop:disable Naming/PredicateName
|
162
170
|
defined?(@is_text_run) && @is_text_run && !contains_rich_text?
|
163
171
|
end
|
164
172
|
|
@@ -168,12 +176,12 @@ module Axlsx
|
|
168
176
|
|
169
177
|
# Indicates if the cell is good for shared string table
|
170
178
|
def plain_string?
|
171
|
-
(type == :string || type == :text) &&
|
172
|
-
!
|
173
|
-
|
174
|
-
|
175
|
-
!is_formula? &&
|
176
|
-
!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?
|
177
185
|
end
|
178
186
|
|
179
187
|
# The inline font_name property for the cell
|
@@ -274,15 +282,13 @@ module Axlsx
|
|
274
282
|
def extend=(v) set_run_style :validate_boolean, :extend, v; end
|
275
283
|
|
276
284
|
# The inline underline property for the cell.
|
277
|
-
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
285
|
+
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
278
286
|
# @return [Boolean]
|
279
287
|
# @return [String]
|
280
|
-
# @note true is for backwards compatability and is reassigned to :single
|
281
288
|
attr_reader :u
|
282
289
|
|
283
290
|
# @see u
|
284
291
|
def u=(v)
|
285
|
-
v = :single if (v == true || v == 1 || v == :true || v == 'true')
|
286
292
|
set_run_style :validate_cell_u, :u, v
|
287
293
|
end
|
288
294
|
|
@@ -292,7 +298,7 @@ module Axlsx
|
|
292
298
|
|
293
299
|
# @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
|
294
300
|
def color=(v)
|
295
|
-
@color = v.is_a?(Color) ? v : Color.new(:
|
301
|
+
@color = v.is_a?(Color) ? v : Color.new(rgb: v)
|
296
302
|
@is_text_run = true
|
297
303
|
end
|
298
304
|
|
@@ -338,20 +344,20 @@ module Axlsx
|
|
338
344
|
# @example Relative Cell Reference
|
339
345
|
# ws.rows.first.cells.first.r #=> "A1"
|
340
346
|
def r
|
341
|
-
Axlsx
|
347
|
+
Axlsx.cell_r index, @row.row_index
|
342
348
|
end
|
343
349
|
|
344
|
-
# @return [String] The absolute alpha(column)numeric(row) reference for this
|
350
|
+
# @return [String] The absolute alpha(column)numeric(row) reference for this cell.
|
345
351
|
# @example Absolute Cell Reference
|
346
352
|
# ws.rows.first.cells.first.r #=> "$A$1"
|
347
353
|
def r_abs
|
348
|
-
"$#{
|
354
|
+
"$#{CELL_REFERENCE_REGEX.match(r)[1, 2].join('$')}"
|
349
355
|
end
|
350
356
|
|
351
357
|
# @return [Integer] The cellXfs item index applied to this cell.
|
352
358
|
# @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
|
353
359
|
def style=(v)
|
354
|
-
Axlsx
|
360
|
+
Axlsx.validate_unsigned_int(v)
|
355
361
|
count = styles.cellXfs.size
|
356
362
|
raise ArgumentError, "Invalid cellXfs id" unless v < count
|
357
363
|
|
@@ -368,11 +374,11 @@ module Axlsx
|
|
368
374
|
# @param [Cell, String] target The last cell, or str ref for the cell in the merge range
|
369
375
|
def merge(target)
|
370
376
|
start, stop = if target.is_a?(String)
|
371
|
-
[
|
377
|
+
[r, target]
|
372
378
|
elsif target.is_a?(Cell)
|
373
|
-
Axlsx.sort_cells([self, target]).map
|
379
|
+
Axlsx.sort_cells([self, target]).map(&:r)
|
374
380
|
end
|
375
|
-
|
381
|
+
row.worksheet.merge_cells "#{start}:#{stop}" unless stop.nil?
|
376
382
|
end
|
377
383
|
|
378
384
|
# Serializes the cell
|
@@ -380,20 +386,22 @@ module Axlsx
|
|
380
386
|
# @param [Integer] c_index The cell index in the row.
|
381
387
|
# @param [String] str The string index the cell content will be appended to. Defaults to empty string.
|
382
388
|
# @return [String] xml text for the cell
|
383
|
-
def to_xml_string(r_index, c_index, str = '')
|
389
|
+
def to_xml_string(r_index, c_index, str = +'')
|
384
390
|
CellSerializer.to_xml_string r_index, c_index, self, str
|
385
391
|
end
|
386
392
|
|
387
|
-
def is_formula?
|
393
|
+
def is_formula? # rubocop:disable Naming/PredicateName
|
388
394
|
return false if escape_formulas
|
389
395
|
|
390
|
-
type == :string && @value.to_s.start_with?(
|
396
|
+
type == :string && @value.to_s.start_with?(FORMULA_PREFIX)
|
391
397
|
end
|
392
398
|
|
393
|
-
def is_array_formula?
|
399
|
+
def is_array_formula? # rubocop:disable Naming/PredicateName
|
394
400
|
return false if escape_formulas
|
395
401
|
|
396
|
-
type == :string &&
|
402
|
+
type == :string &&
|
403
|
+
@value.to_s.start_with?(ARRAY_FORMULA_PREFIX) &&
|
404
|
+
@value.to_s.end_with?(ARRAY_FORMULA_SUFFIX)
|
397
405
|
end
|
398
406
|
|
399
407
|
# returns the absolute or relative string style reference for
|
@@ -417,7 +425,7 @@ module Axlsx
|
|
417
425
|
# Attempts to determine the correct width for this cell's content
|
418
426
|
# @return [Float]
|
419
427
|
def autowidth
|
420
|
-
return if
|
428
|
+
return if value.nil? || is_formula?
|
421
429
|
|
422
430
|
if contains_rich_text?
|
423
431
|
string_width('', font_size) + value.autowidth
|
@@ -433,12 +441,13 @@ module Axlsx
|
|
433
441
|
end
|
434
442
|
end
|
435
443
|
|
436
|
-
# Returns the
|
437
|
-
# 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
|
438
446
|
# processing time in benchmarking...
|
447
|
+
# @return [String] The sanitized value
|
439
448
|
def clean_value
|
440
|
-
if (type == :string || type == :text) && !Axlsx
|
441
|
-
Axlsx
|
449
|
+
if (type == :string || type == :text) && !Axlsx.trust_input
|
450
|
+
Axlsx.sanitize(::CGI.escapeHTML(@value.to_s))
|
442
451
|
else
|
443
452
|
@value.to_s
|
444
453
|
end
|
@@ -473,13 +482,13 @@ module Axlsx
|
|
473
482
|
return unless INLINE_STYLES.include?(attr.to_sym)
|
474
483
|
|
475
484
|
Axlsx.send(validator, value) unless validator.nil?
|
476
|
-
|
485
|
+
instance_variable_set :"@#{attr}", value
|
477
486
|
@is_text_run = true
|
478
487
|
end
|
479
488
|
|
480
489
|
# @see ssti
|
481
490
|
def ssti=(v)
|
482
|
-
Axlsx
|
491
|
+
Axlsx.validate_unsigned_int(v)
|
483
492
|
@ssti = v
|
484
493
|
end
|
485
494
|
|
@@ -498,13 +507,11 @@ module Axlsx
|
|
498
507
|
:time
|
499
508
|
elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
500
509
|
:boolean
|
501
|
-
elsif v.
|
510
|
+
elsif v.respond_to?(:to_i) && Axlsx::NUMERIC_REGEX.match?(v.to_s)
|
502
511
|
:integer
|
503
|
-
elsif v.
|
504
|
-
:float
|
505
|
-
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)))
|
506
513
|
:float
|
507
|
-
elsif v.to_s
|
514
|
+
elsif Axlsx::ISO_8601_REGEX.match?(v.to_s)
|
508
515
|
:iso_8601
|
509
516
|
elsif v.is_a? RichText
|
510
517
|
:richtext
|
@@ -518,18 +525,18 @@ module Axlsx
|
|
518
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.
|
519
526
|
# @see Axlsx#date1904
|
520
527
|
def cast_value(v)
|
521
|
-
return v if v.
|
528
|
+
return v if v.nil? || v.is_a?(RichText)
|
522
529
|
|
523
530
|
case type
|
524
531
|
when :date
|
525
|
-
self.style = STYLE_DATE if
|
532
|
+
self.style = STYLE_DATE if style.zero?
|
526
533
|
if !v.is_a?(Date) && v.respond_to?(:to_date)
|
527
534
|
v.to_date
|
528
535
|
else
|
529
536
|
v
|
530
537
|
end
|
531
538
|
when :time
|
532
|
-
self.style = STYLE_DATE if
|
539
|
+
self.style = STYLE_DATE if style.zero?
|
533
540
|
if !v.is_a?(Time) && v.respond_to?(:to_time)
|
534
541
|
v.to_time
|
535
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
|