caxlsx 3.4.1 → 4.1.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 +24 -1
- data/README.md +9 -11
- data/Rakefile +7 -5
- data/examples/generate.rb +3 -1
- data/lib/axlsx/content_type/abstract_content_type.rb +12 -4
- data/lib/axlsx/content_type/content_type.rb +8 -6
- data/lib/axlsx/content_type/default.rb +7 -2
- data/lib/axlsx/content_type/override.rb +7 -2
- data/lib/axlsx/doc_props/app.rb +95 -26
- 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 +20 -12
- data/lib/axlsx/drawing/ax_data_source.rb +2 -0
- data/lib/axlsx/drawing/axes.rb +6 -4
- data/lib/axlsx/drawing/axis.rb +42 -22
- 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 +20 -9
- 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 +29 -12
- data/lib/axlsx/drawing/chart.rb +46 -20
- data/lib/axlsx/drawing/d_lbls.rb +10 -8
- data/lib/axlsx/drawing/drawing.rb +59 -56
- data/lib/axlsx/drawing/graphic_frame.rb +6 -4
- data/lib/axlsx/drawing/hyperlink.rb +19 -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 +20 -12
- data/lib/axlsx/drawing/marker.rb +24 -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 +13 -5
- data/lib/axlsx/drawing/pic.rb +26 -15
- data/lib/axlsx/drawing/picture_locking.rb +3 -1
- data/lib/axlsx/drawing/pie_3D_chart.rb +6 -4
- data/lib/axlsx/drawing/pie_chart.rb +36 -0
- data/lib/axlsx/drawing/pie_series.rb +23 -9
- data/lib/axlsx/drawing/scaling.rb +25 -9
- 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 +13 -5
- data/lib/axlsx/drawing/series.rb +13 -5
- 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 +16 -8
- data/lib/axlsx/drawing/vml_drawing.rb +18 -16
- data/lib/axlsx/drawing/vml_shape.rb +24 -22
- data/lib/axlsx/package.rb +73 -67
- data/lib/axlsx/rels/relationship.rb +21 -6
- data/lib/axlsx/rels/relationships.rb +6 -4
- data/lib/axlsx/stylesheet/border.rb +15 -4
- data/lib/axlsx/stylesheet/border_pr.rb +19 -6
- data/lib/axlsx/stylesheet/cell_alignment.rb +41 -10
- data/lib/axlsx/stylesheet/cell_protection.rb +12 -3
- data/lib/axlsx/stylesheet/cell_style.rb +33 -8
- data/lib/axlsx/stylesheet/color.rb +15 -7
- data/lib/axlsx/stylesheet/dxf.rb +34 -9
- data/lib/axlsx/stylesheet/fill.rb +7 -2
- data/lib/axlsx/stylesheet/font.rb +65 -17
- data/lib/axlsx/stylesheet/gradient_fill.rb +12 -4
- data/lib/axlsx/stylesheet/gradient_stop.rb +14 -5
- data/lib/axlsx/stylesheet/num_fmt.rb +14 -10
- data/lib/axlsx/stylesheet/pattern_fill.rb +18 -5
- data/lib/axlsx/stylesheet/styles.rb +124 -82
- data/lib/axlsx/stylesheet/table_style.rb +19 -6
- data/lib/axlsx/stylesheet/table_style_element.rb +15 -4
- data/lib/axlsx/stylesheet/table_styles.rb +14 -5
- data/lib/axlsx/stylesheet/xf.rb +73 -18
- data/lib/axlsx/util/accessors.rb +10 -6
- 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 +4 -2
- data/lib/axlsx/workbook/shared_strings_table.rb +8 -6
- data/lib/axlsx/workbook/workbook.rb +94 -79
- data/lib/axlsx/workbook/workbook_view.rb +3 -1
- data/lib/axlsx/workbook/workbook_views.rb +4 -2
- data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +65 -8
- data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +11 -5
- 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 +83 -64
- data/lib/axlsx/workbook/worksheet/cell_serializer.rb +31 -27
- data/lib/axlsx/workbook/worksheet/cfvo.rb +11 -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 +6 -4
- data/lib/axlsx/workbook/worksheet/color_scale.rb +12 -10
- data/lib/axlsx/workbook/worksheet/cols.rb +4 -2
- 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 +16 -5
- data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +73 -16
- data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +4 -2
- data/lib/axlsx/workbook/worksheet/data_bar.rb +14 -13
- data/lib/axlsx/workbook/worksheet/data_validation.rb +69 -28
- data/lib/axlsx/workbook/worksheet/data_validations.rb +4 -2
- 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 +38 -9
- data/lib/axlsx/workbook/worksheet/merged_cells.rb +6 -6
- data/lib/axlsx/workbook/worksheet/outline_pr.rb +6 -2
- data/lib/axlsx/workbook/worksheet/page_margins.rb +39 -11
- data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +7 -4
- data/lib/axlsx/workbook/worksheet/page_setup.rb +34 -9
- data/lib/axlsx/workbook/worksheet/pane.rb +17 -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 +3 -1
- 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 +6 -4
- data/lib/axlsx/workbook/worksheet/rich_text.rb +3 -1
- data/lib/axlsx/workbook/worksheet/rich_text_run.rb +46 -24
- data/lib/axlsx/workbook/worksheet/row.rb +11 -9
- data/lib/axlsx/workbook/worksheet/row_breaks.rb +7 -5
- data/lib/axlsx/workbook/worksheet/selection.rb +15 -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 +11 -9
- data/lib/axlsx/workbook/worksheet/sheet_view.rb +38 -15
- 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 +4 -2
- data/lib/axlsx/workbook/worksheet/worksheet.rb +56 -39
- 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 +7 -5
- data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +5 -3
- data/lib/axlsx.rb +56 -42
- data/lib/caxlsx.rb +3 -1
- metadata +39 -71
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Axlsx
|
2
4
|
# When multiple values are chosen to filter by, or when a group of date values are chosen to filter by,
|
3
5
|
# this object groups those criteria together.
|
@@ -22,7 +24,7 @@ module Axlsx
|
|
22
24
|
serializable_attributes :blank, :calendar_type
|
23
25
|
|
24
26
|
# Allowed calendar types
|
25
|
-
CALENDAR_TYPES = %w(gregorian gregorianUs gregorianMeFrench gregorianArabic hijri hebrew taiwan japan thai korea saka gregorianXlitEnglish gregorianXlitFrench none)
|
27
|
+
CALENDAR_TYPES = %w(gregorian gregorianUs gregorianMeFrench gregorianArabic hijri hebrew taiwan japan thai korea saka gregorianXlitEnglish gregorianXlitFrench none).freeze
|
26
28
|
|
27
29
|
# Flag indicating whether to filter by blank.
|
28
30
|
# @return [Boolean]
|
@@ -74,8 +76,10 @@ module Axlsx
|
|
74
76
|
end
|
75
77
|
|
76
78
|
# Serialize the object to xml
|
77
|
-
def to_xml_string(str = '')
|
78
|
-
str <<
|
79
|
+
def to_xml_string(str = +'')
|
80
|
+
str << '<filters '
|
81
|
+
serialized_attributes(str)
|
82
|
+
str << '>'
|
79
83
|
filter_items.each { |filter| filter.to_xml_string(str) }
|
80
84
|
date_group_items.each { |date_group_item| date_group_item.to_xml_string(str) }
|
81
85
|
str << '</filters>'
|
@@ -118,8 +122,8 @@ module Axlsx
|
|
118
122
|
|
119
123
|
# Serializes the filter value object
|
120
124
|
# @param [String] str The string to concact the serialization information to.
|
121
|
-
def to_xml_string(str = '')
|
122
|
-
str << "<filter val='#{@val
|
125
|
+
def to_xml_string(str = +'')
|
126
|
+
str << "<filter val='#{@val}' />"
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
@@ -153,7 +157,7 @@ module Axlsx
|
|
153
157
|
serializable_attributes :date_time_grouping, :year, :month, :day, :hour, :minute, :second
|
154
158
|
|
155
159
|
# Allowed date time groupings
|
156
|
-
DATE_TIME_GROUPING = %w(year month day hour minute second)
|
160
|
+
DATE_TIME_GROUPING = %w(year month day hour minute second).freeze
|
157
161
|
|
158
162
|
# Grouping level
|
159
163
|
# This must be one of year, month, day, hour, minute or second.
|
@@ -235,7 +239,7 @@ module Axlsx
|
|
235
239
|
|
236
240
|
# Serialize the object to xml
|
237
241
|
# @param [String] str The string object this serialization will be concatenated to.
|
238
|
-
def to_xml_string(str = '')
|
242
|
+
def to_xml_string(str = +'')
|
239
243
|
serialized_tag('dateGroupItem', str)
|
240
244
|
end
|
241
245
|
end
|
@@ -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
|
@@ -187,7 +189,9 @@ module Axlsx
|
|
187
189
|
attr_reader :font_name
|
188
190
|
|
189
191
|
# @see font_name
|
190
|
-
def font_name=(v)
|
192
|
+
def font_name=(v)
|
193
|
+
set_run_style :validate_string, :font_name, v
|
194
|
+
end
|
191
195
|
|
192
196
|
# The inline charset property for the cell
|
193
197
|
# As far as I can tell, this is pretty much ignored. However, based on the spec it should be one of the following:
|
@@ -214,7 +218,9 @@ module Axlsx
|
|
214
218
|
attr_reader :charset
|
215
219
|
|
216
220
|
# @see charset
|
217
|
-
def charset=(v)
|
221
|
+
def charset=(v)
|
222
|
+
set_run_style :validate_unsigned_int, :charset, v
|
223
|
+
end
|
218
224
|
|
219
225
|
# The inline family property for the cell
|
220
226
|
# @return [Integer]
|
@@ -235,60 +241,72 @@ module Axlsx
|
|
235
241
|
attr_reader :b
|
236
242
|
|
237
243
|
# @see b
|
238
|
-
def b=(v)
|
244
|
+
def b=(v)
|
245
|
+
set_run_style :validate_boolean, :b, v
|
246
|
+
end
|
239
247
|
|
240
248
|
# The inline italic property for the cell
|
241
249
|
# @return [Boolean]
|
242
250
|
attr_reader :i
|
243
251
|
|
244
252
|
# @see i
|
245
|
-
def i=(v)
|
253
|
+
def i=(v)
|
254
|
+
set_run_style :validate_boolean, :i, v
|
255
|
+
end
|
246
256
|
|
247
257
|
# The inline strike property for the cell
|
248
258
|
# @return [Boolean]
|
249
259
|
attr_reader :strike
|
250
260
|
|
251
261
|
# @see strike
|
252
|
-
def strike=(v)
|
262
|
+
def strike=(v)
|
263
|
+
set_run_style :validate_boolean, :strike, v
|
264
|
+
end
|
253
265
|
|
254
266
|
# The inline outline property for the cell
|
255
267
|
# @return [Boolean]
|
256
268
|
attr_reader :outline
|
257
269
|
|
258
270
|
# @see outline
|
259
|
-
def outline=(v)
|
271
|
+
def outline=(v)
|
272
|
+
set_run_style :validate_boolean, :outline, v
|
273
|
+
end
|
260
274
|
|
261
275
|
# The inline shadow property for the cell
|
262
276
|
# @return [Boolean]
|
263
277
|
attr_reader :shadow
|
264
278
|
|
265
279
|
# @see shadow
|
266
|
-
def shadow=(v)
|
280
|
+
def shadow=(v)
|
281
|
+
set_run_style :validate_boolean, :shadow, v
|
282
|
+
end
|
267
283
|
|
268
284
|
# The inline condense property for the cell
|
269
285
|
# @return [Boolean]
|
270
286
|
attr_reader :condense
|
271
287
|
|
272
288
|
# @see condense
|
273
|
-
def condense=(v)
|
289
|
+
def condense=(v)
|
290
|
+
set_run_style :validate_boolean, :condense, v
|
291
|
+
end
|
274
292
|
|
275
293
|
# The inline extend property for the cell
|
276
294
|
# @return [Boolean]
|
277
295
|
attr_reader :extend
|
278
296
|
|
279
297
|
# @see extend
|
280
|
-
def extend=(v)
|
298
|
+
def extend=(v)
|
299
|
+
set_run_style :validate_boolean, :extend, v
|
300
|
+
end
|
281
301
|
|
282
302
|
# The inline underline property for the cell.
|
283
|
-
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
303
|
+
# It must be one of :none, :single, :double, :singleAccounting, :doubleAccounting
|
284
304
|
# @return [Boolean]
|
285
305
|
# @return [String]
|
286
|
-
# @note true is for backwards compatability and is reassigned to :single
|
287
306
|
attr_reader :u
|
288
307
|
|
289
308
|
# @see u
|
290
309
|
def u=(v)
|
291
|
-
v = :single if (v == true || v == 1 || v == :true || v == 'true')
|
292
310
|
set_run_style :validate_cell_u, :u, v
|
293
311
|
end
|
294
312
|
|
@@ -298,7 +316,7 @@ module Axlsx
|
|
298
316
|
|
299
317
|
# @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
|
300
318
|
def color=(v)
|
301
|
-
@color = v.is_a?(Color) ? v : Color.new(:
|
319
|
+
@color = v.is_a?(Color) ? v : Color.new(rgb: v)
|
302
320
|
@is_text_run = true
|
303
321
|
end
|
304
322
|
|
@@ -307,7 +325,9 @@ module Axlsx
|
|
307
325
|
attr_reader :sz
|
308
326
|
|
309
327
|
# @see sz
|
310
|
-
def sz=(v)
|
328
|
+
def sz=(v)
|
329
|
+
set_run_style :validate_unsigned_int, :sz, v
|
330
|
+
end
|
311
331
|
|
312
332
|
# The inline vertical alignment property for the cell
|
313
333
|
# this must be one of [:baseline, :subscript, :superscript]
|
@@ -344,20 +364,20 @@ module Axlsx
|
|
344
364
|
# @example Relative Cell Reference
|
345
365
|
# ws.rows.first.cells.first.r #=> "A1"
|
346
366
|
def r
|
347
|
-
Axlsx
|
367
|
+
Axlsx.cell_r index, @row.row_index
|
348
368
|
end
|
349
369
|
|
350
|
-
# @return [String] The absolute alpha(column)numeric(row) reference for this
|
370
|
+
# @return [String] The absolute alpha(column)numeric(row) reference for this cell.
|
351
371
|
# @example Absolute Cell Reference
|
352
372
|
# ws.rows.first.cells.first.r #=> "$A$1"
|
353
373
|
def r_abs
|
354
|
-
"$#{
|
374
|
+
"$#{CELL_REFERENCE_REGEX.match(r)[1, 2].join('$')}"
|
355
375
|
end
|
356
376
|
|
357
377
|
# @return [Integer] The cellXfs item index applied to this cell.
|
358
378
|
# @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
|
359
379
|
def style=(v)
|
360
|
-
Axlsx
|
380
|
+
Axlsx.validate_unsigned_int(v)
|
361
381
|
count = styles.cellXfs.size
|
362
382
|
raise ArgumentError, "Invalid cellXfs id" unless v < count
|
363
383
|
|
@@ -374,11 +394,11 @@ module Axlsx
|
|
374
394
|
# @param [Cell, String] target The last cell, or str ref for the cell in the merge range
|
375
395
|
def merge(target)
|
376
396
|
start, stop = if target.is_a?(String)
|
377
|
-
[
|
397
|
+
[r, target]
|
378
398
|
elsif target.is_a?(Cell)
|
379
|
-
Axlsx.sort_cells([self, target]).map
|
399
|
+
Axlsx.sort_cells([self, target]).map(&:r)
|
380
400
|
end
|
381
|
-
|
401
|
+
row.worksheet.merge_cells "#{start}:#{stop}" unless stop.nil?
|
382
402
|
end
|
383
403
|
|
384
404
|
# Serializes the cell
|
@@ -386,21 +406,21 @@ module Axlsx
|
|
386
406
|
# @param [Integer] c_index The cell index in the row.
|
387
407
|
# @param [String] str The string index the cell content will be appended to. Defaults to empty string.
|
388
408
|
# @return [String] xml text for the cell
|
389
|
-
def to_xml_string(r_index, c_index, str = '')
|
409
|
+
def to_xml_string(r_index, c_index, str = +'')
|
390
410
|
CellSerializer.to_xml_string r_index, c_index, self, str
|
391
411
|
end
|
392
412
|
|
393
|
-
def is_formula?
|
413
|
+
def is_formula? # rubocop:disable Naming/PredicateName
|
394
414
|
return false if escape_formulas
|
395
415
|
|
396
|
-
type == :string && @value.to_s.start_with?(
|
416
|
+
type == :string && @value.to_s.start_with?(FORMULA_PREFIX)
|
397
417
|
end
|
398
418
|
|
399
|
-
def is_array_formula?
|
419
|
+
def is_array_formula? # rubocop:disable Naming/PredicateName
|
400
420
|
return false if escape_formulas
|
401
421
|
|
402
422
|
type == :string &&
|
403
|
-
@value.to_s.start_with?(
|
423
|
+
@value.to_s.start_with?(ARRAY_FORMULA_PREFIX) &&
|
404
424
|
@value.to_s.end_with?(ARRAY_FORMULA_SUFFIX)
|
405
425
|
end
|
406
426
|
|
@@ -425,7 +445,7 @@ module Axlsx
|
|
425
445
|
# Attempts to determine the correct width for this cell's content
|
426
446
|
# @return [Float]
|
427
447
|
def autowidth
|
428
|
-
return if
|
448
|
+
return if value.nil? || is_formula?
|
429
449
|
|
430
450
|
if contains_rich_text?
|
431
451
|
string_width('', font_size) + value.autowidth
|
@@ -441,12 +461,13 @@ module Axlsx
|
|
441
461
|
end
|
442
462
|
end
|
443
463
|
|
444
|
-
# Returns the
|
445
|
-
# TODO find a better way to do this as it accounts for 30% of
|
464
|
+
# Returns the sanitized value
|
465
|
+
# TODO: find a better way to do this as it accounts for 30% of
|
446
466
|
# processing time in benchmarking...
|
467
|
+
# @return [String] The sanitized value
|
447
468
|
def clean_value
|
448
|
-
if (type == :string || type == :text) && !Axlsx
|
449
|
-
Axlsx
|
469
|
+
if (type == :string || type == :text) && !Axlsx.trust_input
|
470
|
+
Axlsx.sanitize(::CGI.escapeHTML(@value.to_s))
|
450
471
|
else
|
451
472
|
@value.to_s
|
452
473
|
end
|
@@ -481,13 +502,13 @@ module Axlsx
|
|
481
502
|
return unless INLINE_STYLES.include?(attr.to_sym)
|
482
503
|
|
483
504
|
Axlsx.send(validator, value) unless validator.nil?
|
484
|
-
|
505
|
+
instance_variable_set :"@#{attr}", value
|
485
506
|
@is_text_run = true
|
486
507
|
end
|
487
508
|
|
488
509
|
# @see ssti
|
489
510
|
def ssti=(v)
|
490
|
-
Axlsx
|
511
|
+
Axlsx.validate_unsigned_int(v)
|
491
512
|
@ssti = v
|
492
513
|
end
|
493
514
|
|
@@ -506,13 +527,11 @@ module Axlsx
|
|
506
527
|
:time
|
507
528
|
elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
508
529
|
:boolean
|
509
|
-
elsif v.
|
530
|
+
elsif v.respond_to?(:to_i) && Axlsx::NUMERIC_REGEX.match?(v.to_s)
|
510
531
|
: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)
|
532
|
+
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
533
|
:float
|
515
|
-
elsif v.to_s
|
534
|
+
elsif Axlsx::ISO_8601_REGEX.match?(v.to_s)
|
516
535
|
:iso_8601
|
517
536
|
elsif v.is_a? RichText
|
518
537
|
:richtext
|
@@ -526,18 +545,18 @@ module Axlsx
|
|
526
545
|
# 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
546
|
# @see Axlsx#date1904
|
528
547
|
def cast_value(v)
|
529
|
-
return v if v.
|
548
|
+
return v if v.nil? || v.is_a?(RichText)
|
530
549
|
|
531
550
|
case type
|
532
551
|
when :date
|
533
|
-
self.style = STYLE_DATE if
|
552
|
+
self.style = STYLE_DATE if style.zero?
|
534
553
|
if !v.is_a?(Date) && v.respond_to?(:to_date)
|
535
554
|
v.to_date
|
536
555
|
else
|
537
556
|
v
|
538
557
|
end
|
539
558
|
when :time
|
540
|
-
self.style = STYLE_DATE if
|
559
|
+
self.style = STYLE_DATE if style.zero?
|
541
560
|
if !v.is_a?(Time) && v.respond_to?(:to_time)
|
542
561
|
v.to_time
|
543
562
|
else
|