axlsx 1.0.16 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. data/.yardopts +1 -0
  2. data/CHANGELOG.md +18 -3
  3. data/README.md +189 -55
  4. data/examples/example.csv +1000 -0
  5. data/examples/example.rb +264 -142
  6. data/examples/example.xlsx +0 -0
  7. data/examples/example_streamed.xlsx +0 -0
  8. data/examples/no-use_autowidth.xlsx +0 -0
  9. data/examples/shared_strings_example.xlsx +0 -0
  10. data/lib/axlsx/content_type/content_type.rb +13 -12
  11. data/lib/axlsx/content_type/default.rb +10 -6
  12. data/lib/axlsx/content_type/override.rb +13 -8
  13. data/lib/axlsx/doc_props/app.rb +38 -41
  14. data/lib/axlsx/doc_props/core.rb +13 -17
  15. data/lib/axlsx/drawing/axis.rb +39 -19
  16. data/lib/axlsx/drawing/bar_3D_chart.rb +34 -32
  17. data/lib/axlsx/drawing/bar_series.rb +14 -14
  18. data/lib/axlsx/drawing/cat_axis.rb +16 -14
  19. data/lib/axlsx/drawing/cat_axis_data.rb +17 -18
  20. data/lib/axlsx/drawing/chart.rb +40 -41
  21. data/lib/axlsx/drawing/drawing.rb +16 -12
  22. data/lib/axlsx/drawing/graphic_frame.rb +22 -21
  23. data/lib/axlsx/drawing/hyperlink.rb +13 -12
  24. data/lib/axlsx/drawing/line_3D_chart.rb +31 -28
  25. data/lib/axlsx/drawing/line_series.rb +12 -11
  26. data/lib/axlsx/drawing/marker.rb +11 -8
  27. data/lib/axlsx/drawing/named_axis_data.rb +36 -0
  28. data/lib/axlsx/drawing/one_cell_anchor.rb +18 -16
  29. data/lib/axlsx/drawing/pic.rb +26 -38
  30. data/lib/axlsx/drawing/picture_locking.rb +22 -18
  31. data/lib/axlsx/drawing/pie_3D_chart.rb +11 -8
  32. data/lib/axlsx/drawing/pie_series.rb +16 -12
  33. data/lib/axlsx/drawing/scaling.rb +11 -10
  34. data/lib/axlsx/drawing/scatter_chart.rb +69 -0
  35. data/lib/axlsx/drawing/scatter_series.rb +39 -0
  36. data/lib/axlsx/drawing/ser_axis.rb +11 -10
  37. data/lib/axlsx/drawing/series.rb +16 -15
  38. data/lib/axlsx/drawing/series_title.rb +15 -14
  39. data/lib/axlsx/drawing/title.rb +27 -26
  40. data/lib/axlsx/drawing/two_cell_anchor.rb +19 -20
  41. data/lib/axlsx/drawing/val_axis.rb +9 -7
  42. data/lib/axlsx/drawing/val_axis_data.rb +18 -17
  43. data/lib/axlsx/drawing/view_3D.rb +23 -20
  44. data/lib/axlsx/package.rb +116 -51
  45. data/lib/axlsx/rels/relationship.rb +12 -8
  46. data/lib/axlsx/rels/relationships.rb +8 -1
  47. data/lib/axlsx/stylesheet/#num_fmt.rb# +69 -0
  48. data/lib/axlsx/stylesheet/border.rb +28 -23
  49. data/lib/axlsx/stylesheet/border_pr.rb +17 -15
  50. data/lib/axlsx/stylesheet/cell_alignment.rb +24 -21
  51. data/lib/axlsx/stylesheet/cell_protection.rb +11 -7
  52. data/lib/axlsx/stylesheet/cell_style.rb +9 -5
  53. data/lib/axlsx/stylesheet/color.rb +21 -14
  54. data/lib/axlsx/stylesheet/fill.rb +8 -5
  55. data/lib/axlsx/stylesheet/font.rb +22 -14
  56. data/lib/axlsx/stylesheet/gradient_fill.rb +20 -17
  57. data/lib/axlsx/stylesheet/gradient_stop.rb +10 -6
  58. data/lib/axlsx/stylesheet/num_fmt.rb +13 -6
  59. data/lib/axlsx/stylesheet/pattern_fill.rb +26 -10
  60. data/lib/axlsx/stylesheet/styles.rb +53 -41
  61. data/lib/axlsx/stylesheet/table_style.rb +10 -4
  62. data/lib/axlsx/stylesheet/table_style_element.rb +11 -7
  63. data/lib/axlsx/stylesheet/table_styles.rb +12 -8
  64. data/lib/axlsx/stylesheet/xf.rb +30 -25
  65. data/lib/axlsx/util/cbf.rb +1 -0
  66. data/lib/axlsx/util/constants.rb +27 -14
  67. data/lib/axlsx/util/ms_off_crypto.rb +1 -1
  68. data/lib/axlsx/util/parser.rb +1 -0
  69. data/lib/axlsx/util/simple_typed_list.rb +20 -10
  70. data/lib/axlsx/util/storage.rb +1 -0
  71. data/lib/axlsx/util/validators.rb +23 -7
  72. data/lib/axlsx/version.rb +2 -1
  73. data/lib/axlsx/workbook/shared_strings_table.rb +69 -0
  74. data/lib/axlsx/workbook/shared_strings_table.rb~ +69 -0
  75. data/lib/axlsx/workbook/workbook.rb +81 -35
  76. data/lib/axlsx/workbook/worksheet/cell.rb +172 -117
  77. data/lib/axlsx/workbook/worksheet/col.rb +114 -0
  78. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  79. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +29 -0
  80. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -0
  81. data/lib/axlsx/workbook/worksheet/row.rb +53 -21
  82. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  83. data/lib/axlsx/workbook/worksheet/table.rb +96 -0
  84. data/lib/axlsx/workbook/worksheet/table.rb~ +97 -0
  85. data/lib/axlsx/workbook/worksheet/worksheet.rb +269 -121
  86. data/lib/axlsx.rb +41 -14
  87. data/lib/schema/dc.xsd +5 -5
  88. data/lib/schema/dcmitype.xsd +5 -3
  89. data/lib/schema/dcterms.xsd +15 -15
  90. data/lib/schema/opc-coreProperties.xsd +6 -2
  91. data/lib/schema/xml.xsd +7 -8
  92. data/test/#benchmark.txt# +7 -0
  93. data/test/#tc_helper.rb# +3 -0
  94. data/test/benchmark.rb +81 -0
  95. data/test/benchmark.rb~ +0 -0
  96. data/test/benchmark.txt +6 -0
  97. data/test/benchmark.txt~ +6 -0
  98. data/test/content_type/tc_content_type.rb +31 -31
  99. data/test/content_type/tc_default.rb +9 -22
  100. data/test/content_type/tc_override.rb +8 -21
  101. data/test/doc_props/tc_app.rb +2 -8
  102. data/test/doc_props/tc_core.rb +6 -7
  103. data/test/drawing/tc_axis.rb +7 -3
  104. data/test/drawing/tc_bar_3D_chart.rb +6 -7
  105. data/test/drawing/tc_bar_series.rb +4 -5
  106. data/test/drawing/tc_cat_axis.rb +2 -3
  107. data/test/drawing/tc_cat_axis_data.rb +2 -3
  108. data/test/drawing/tc_chart.rb +13 -14
  109. data/test/drawing/tc_drawing.rb +7 -8
  110. data/test/drawing/tc_graphic_frame.rb +3 -4
  111. data/test/drawing/tc_hyperlink.rb +2 -3
  112. data/test/drawing/tc_line_3d_chart.rb +5 -6
  113. data/test/drawing/tc_line_series.rb +3 -4
  114. data/test/drawing/tc_marker.rb +3 -4
  115. data/test/drawing/tc_one_cell_anchor.rb +6 -7
  116. data/test/drawing/tc_pic.rb +8 -9
  117. data/test/drawing/tc_picture_locking.rb +2 -3
  118. data/test/drawing/tc_pie_3D_chart.rb +5 -6
  119. data/test/drawing/tc_pie_series.rb +4 -5
  120. data/test/drawing/tc_scaling.rb +3 -4
  121. data/test/drawing/tc_scatter_chart.rb +43 -0
  122. data/test/drawing/tc_scatter_series.rb +20 -0
  123. data/test/drawing/tc_ser_axis.rb +2 -3
  124. data/test/drawing/tc_series.rb +4 -5
  125. data/test/drawing/tc_series_title.rb +4 -5
  126. data/test/drawing/tc_title.rb +4 -5
  127. data/test/drawing/tc_two_cell_anchor.rb +4 -5
  128. data/test/drawing/tc_val_axis.rb +2 -3
  129. data/test/drawing/tc_val_axis_data.rb +2 -3
  130. data/test/drawing/tc_view_3D.rb +6 -7
  131. data/test/example.csv +1000 -0
  132. data/test/example.xlsx +0 -0
  133. data/test/example_streamed.xlsx +0 -0
  134. data/test/profile.rb +33 -0
  135. data/test/rels/tc_relationship.rb +5 -6
  136. data/test/rels/tc_relationships.rb +4 -5
  137. data/test/stylesheet/tc_border.rb +3 -4
  138. data/test/stylesheet/tc_border_pr.rb +3 -4
  139. data/test/stylesheet/tc_cell_alignment.rb +10 -6
  140. data/test/stylesheet/tc_cell_protection.rb +2 -3
  141. data/test/stylesheet/tc_cell_style.rb +2 -3
  142. data/test/stylesheet/tc_color.rb +2 -3
  143. data/test/stylesheet/tc_fill.rb +1 -2
  144. data/test/stylesheet/tc_font.rb +12 -5
  145. data/test/stylesheet/tc_gradient_fill.rb +1 -2
  146. data/test/stylesheet/tc_gradient_stop.rb +1 -2
  147. data/test/stylesheet/tc_num_fmt.rb +1 -2
  148. data/test/stylesheet/tc_pattern_fill.rb +3 -4
  149. data/test/stylesheet/tc_styles.rb +16 -6
  150. data/test/stylesheet/tc_table_style.rb +2 -3
  151. data/test/stylesheet/tc_table_style_element.rb +2 -3
  152. data/test/stylesheet/tc_table_styles.rb +3 -4
  153. data/test/stylesheet/tc_xf.rb +16 -17
  154. data/test/tc_axlsx.rb +39 -0
  155. data/test/tc_axlsx.rb~ +0 -0
  156. data/test/tc_helper.rb +3 -0
  157. data/test/tc_helper.rb~ +3 -0
  158. data/test/tc_package.rb +43 -9
  159. data/test/util/tc_simple_typed_list.rb +8 -9
  160. data/test/util/tc_validators.rb +7 -8
  161. data/test/workbook/tc_shared_strings_table.rb +38 -0
  162. data/test/workbook/tc_workbook.rb +32 -6
  163. data/test/workbook/worksheet/table/tc_table.rb +71 -0
  164. data/test/workbook/worksheet/table/tc_table.rb~ +72 -0
  165. data/test/workbook/worksheet/tc_cell.rb +70 -13
  166. data/test/workbook/worksheet/tc_col.rb +59 -0
  167. data/test/workbook/worksheet/tc_col.rb~ +10 -0
  168. data/test/workbook/worksheet/tc_date_time_converter.rb +126 -0
  169. data/test/workbook/worksheet/tc_page_margins.rb +97 -0
  170. data/test/workbook/worksheet/tc_row.rb +54 -4
  171. data/test/workbook/worksheet/tc_worksheet.rb +191 -31
  172. metadata +162 -109
  173. data/test/drawing/tc_hyperlink.rb~ +0 -71
@@ -1,53 +1,66 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: UTF-8
2
+ require 'cgi'
2
3
  module Axlsx
3
- # A cell in a worksheet.
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.
5
6
  # @example Manually creating and manipulating Cell objects
6
- # ws = Workbook.new.add_worksheet
7
+ # ws = Workbook.new.add_worksheet
7
8
  # # This is the simple, and recommended way to create cells. Data types will automatically be determined for you.
8
9
  # ws.add_row :values => [1,"fish",Time.now]
9
10
  #
10
11
  # # but you can also do this
11
12
  # r = ws.add_row
12
13
  # r.add_cell 1
13
- #
14
+ #
14
15
  # # or even this
15
16
  # r = ws.add_row
16
17
  # c = Cell.new row, 1, :value=>integer
17
18
  #
18
19
  # # cells can also be accessed via Row#cells. The example here changes the cells type, which will automatically updated the value from 1 to 1.0
19
20
  # r.cells.last.type = :float
20
- #
21
+ #
21
22
  # @note The recommended way to generate cells is via Worksheet#add_row
22
- #
23
+ #
23
24
  # @see Worksheet#add_row
24
25
  class Cell
25
26
 
27
+
28
+ # An array of available inline styes.
29
+ # TODO change this to a hash where each key defines attr name and validator (and any info the validator requires)
30
+ # then move it out to a module so we can re-use in in other classes.
31
+ # needs to define bla=(v) and bla methods on the class that hook into a
32
+ # set_attr method that kicks the suplied validator and updates the instance_variable
33
+ # for the key
34
+ INLINE_STYLES = ['value', 'type', 'font_name', 'charset',
35
+ 'family', 'b', 'i', 'strike','outline',
36
+ 'shadow', 'condense', 'extend', 'u',
37
+ 'vertAlign', 'sz', 'color', 'scheme']
38
+
26
39
  # The index of the cellXfs item to be applied to this cell.
27
- # @return [Integer]
40
+ # @return [Integer]
28
41
  # @see Axlsx::Styles
29
42
  attr_reader :style
30
43
 
31
44
  # The row this cell belongs to.
32
45
  # @return [Row]
33
46
  attr_reader :row
34
-
35
- # The cell's data type. Currently only four types are supported, :time, :float, :integer and :string.
36
- # Changing the type for a cell will recast the value into that type. If no type option is specified in the constructor, the type is
47
+
48
+ # The cell's data type. Currently only six types are supported, :date, :time, :float, :integer, :string and :boolean.
49
+ # Changing the type for a cell will recast the value into that type. If no type option is specified in the constructor, the type is
37
50
  # automatically determed.
38
51
  # @see Cell#cell_type_from_value
39
- # @return [Symbol] The type of data this cell's value is cast to.
40
- # @raise [ArgumentExeption] Cell.type must be one of [:time, :float, :integer, :string]
41
- # @note
52
+ # @return [Symbol] The type of data this cell's value is cast to.
53
+ # @raise [ArgumentExeption] Cell.type must be one of [:date, time, :float, :integer, :string, :boolean]
54
+ # @note
42
55
  # If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
43
- # :string to :integer or :float, type coversions always return 0 or 0.0
56
+ # :string to :integer or :float, type conversions always return 0 or 0.0
44
57
  # :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
45
58
  # No support is currently implemented for parsing time strings.
46
59
  attr_reader :type
47
60
  # @see type
48
- def type=(v)
49
- RestrictionValidator.validate "Cell.type", [:time, :float, :integer, :string], v
50
- @type=v
61
+ def type=(v)
62
+ RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean], v
63
+ @type=v
51
64
  self.value = @value unless @value.nil?
52
65
  end
53
66
 
@@ -60,103 +73,118 @@ module Axlsx
60
73
  #TODO: consider doing value based type determination first?
61
74
  @value = cast_value(v)
62
75
  end
63
-
76
+
77
+
78
+ # Indicates that the cell has one or more of the custom cell styles applied.
79
+ # @return [Boolean]
80
+ def is_text_run?
81
+ @is_text_run ||= false
82
+ end
83
+
84
+
64
85
  # The inline font_name property for the cell
65
86
  # @return [String]
66
87
  attr_reader :font_name
67
88
  # @see font_name
68
- def font_name=(v) Axlsx::validate_string(v); @font_name = v; end
89
+ def font_name=(v) set_run_style :validate_string, :font_name, v; end
69
90
 
70
91
  # The inline charset property for the cell
71
92
  # @return [String]
72
93
  attr_reader :charset
73
94
  # @see charset
74
- def charset=(v) Axlsx::validate_unsigned_int(v); @charset = v; end
95
+ def charset=(v) set_run_style :validate_unsigned_int, :charset, v; end
75
96
 
76
97
  # The inline family property for the cell
77
98
  # @return [String]
78
99
  attr_reader :family
79
100
  # @see family
80
- def family=(v) Axlsx::validate_string(v); @family = v; end
101
+ def family=(v) set_run_style :validate_string, :family, v; end
81
102
 
82
103
  # The inline bold property for the cell
83
104
  # @return [Boolean]
84
105
  attr_reader :b
85
106
  # @see b
86
- def b=(v) Axlsx::validate_boolean(v); @b = v; end
107
+ def b=(v) set_run_style :validate_boolean, :b, v; end
87
108
 
88
109
  # The inline italic property for the cell
89
110
  # @return [Boolean]
90
111
  attr_reader :i
91
112
  # @see i
92
- def i=(v) Axlsx::validate_boolean(v); @i = v; end
113
+ def i=(v) set_run_style :validate_boolean, :i, v; end
93
114
 
94
115
  # The inline strike property for the cell
95
116
  # @return [Boolean]
96
117
  attr_reader :strike
97
118
  # @see strike
98
- def strike=(v) Axlsx::validate_boolean(v); @strike = v; end
119
+ def strike=(v) set_run_style :validate_boolean, :strike, v; end
99
120
 
100
121
  # The inline outline property for the cell
101
122
  # @return [Boolean]
102
123
  attr_reader :outline
103
124
  # @see outline
104
- def outline=(v) Axlsx::validate_boolean(v); @outline = v; end
125
+ def outline=(v) set_run_style :validate_boolean, :outline, v; end
105
126
 
106
127
  # The inline shadow property for the cell
107
128
  # @return [Boolean]
108
129
  attr_reader :shadow
109
130
  # @see shadow
110
- def shadow=(v) Axlsx::validate_boolean(v); @shadow = v; end
131
+ def shadow=(v) set_run_style :validate_boolean, :shadow, v; end
111
132
 
112
133
  # The inline condense property for the cell
113
134
  # @return [Boolean]
114
135
  attr_reader :condense
115
136
  # @see condense
116
- def condense=(v) Axlsx::validate_boolean(v); @condense = v; end
137
+ def condense=(v) set_run_style :validate_boolean, :condense, v; end
117
138
 
118
139
  # The inline extend property for the cell
119
140
  # @return [Boolean]
120
141
  attr_reader :extend
121
142
  # @see extend
122
- def extend=(v) Axlsx::validate_boolean(v); @extend = v; end
143
+ def extend=(v) set_run_style :validate_boolean, :extend, v; end
123
144
 
124
145
  # The inline underline property for the cell
125
146
  # @return [Boolean]
126
147
  attr_reader :u
127
148
  # @see u
128
- def u=(v) Axlsx::validate_boolean(v); @u = v; end
149
+ def u=(v) set_run_style :validate_boolean, :u, v; end
129
150
 
130
151
  # The inline color property for the cell
131
152
  # @return [Color]
132
153
  attr_reader :color
133
154
  # @param [String] The 8 character representation for an rgb color #FFFFFFFF"
134
- def color=(v)
155
+ def color=(v)
135
156
  @color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
157
+ @has_run_style = true
136
158
  end
137
159
 
138
160
  # The inline sz property for the cell
139
161
  # @return [Boolean]
140
162
  attr_reader :sz
141
163
  # @see sz
142
- def sz=(v) Axlsx::validate_unsigned_int(v); @sz = v; end
164
+ def sz=(v) set_run_style :validate_unsigned_int, :sz, v; end
143
165
 
144
166
  # The inline vertical alignment property for the cell
145
167
  # this must be one of [:baseline, :subscript, :superscript]
146
168
  # @return [Symbol]
147
169
  attr_reader :vertAlign
148
170
  # @see vertAlign
149
- def vertAlign=(v) RestrictionValidator.validate "Cell.vertAlign", [:baseline, :subscript, :superscript], v; @vertAlign = v; end
171
+ def vertAlign=(v)
172
+ RestrictionValidator.validate "Cell.vertAlign", [:baseline, :subscript, :superscript], v
173
+ set_run_style nil, :vertAlign, v
174
+ end
150
175
 
151
176
  # The inline scheme property for the cell
152
177
  # this must be one of [:none, major, minor]
153
178
  # @return [Symbol]
154
179
  attr_reader :scheme
155
180
  # @see scheme
156
- def scheme=(v) RestrictionValidator.validate "Cell.schema", [:none, :major, :minor], v; @scheme = v; end
181
+ def scheme=(v)
182
+ RestrictionValidator.validate "Cell.schema", [:none, :major, :minor], v
183
+ set_run_style nil, :scheme, v
184
+ end
157
185
 
158
186
  # @param [Row] row The row this cell belongs to.
159
- # @param [Any] value The value associated with this cell.
187
+ # @param [Any] value The value associated with this cell.
160
188
  # @option options [Symbol] type The intended data type for this cell. If not specified the data type will be determined internally based on the vlue provided.
161
189
  # @option options [Integer] style The index of the cellXfs item to be applied to this cell. If not specified, the default style (0) will be applied.
162
190
  # @option options [String] font_name
@@ -175,9 +203,11 @@ module Axlsx
175
203
  # @option options [String] color an 8 letter rgb specification
176
204
  # @option options [Symbol] scheme must be one of :none, major, :minor
177
205
  def initialize(row, value="", options={})
178
- self.row=row
206
+ self.row=row
207
+ @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
208
+ @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
179
209
  @styles = row.worksheet.workbook.styles
180
- @row.cells << self
210
+ @row.cells << self
181
211
  options.each do |o|
182
212
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
183
213
  end
@@ -186,6 +216,19 @@ module Axlsx
186
216
  @value = cast_value(value)
187
217
  end
188
218
 
219
+ # The Shared Strings Table index for this cell
220
+ # @return [Integer]
221
+ attr_reader :ssti
222
+
223
+ # equality comparison to test value, type and inline style attributes
224
+ # this is how we work out if the cell needs to be added or already exists in the shared strings table
225
+ def shareable_hash
226
+ self_hash = {}
227
+ INLINE_STYLES.each { |style| self_hash[style] = self.instance_variable_get("@" + style) }
228
+ self_hash['color'] = self_hash['color'].instance_values if self_hash['color']
229
+ self_hash
230
+ end
231
+
189
232
  # @return [Integer] The index of the cell in the containing row.
190
233
  def index
191
234
  @row.cells.index(self)
@@ -193,16 +236,17 @@ module Axlsx
193
236
 
194
237
  # @return [String] The alpha(column)numeric(row) reference for this sell.
195
238
  # @example Relative Cell Reference
196
- # ws.rows.first.cells.first.r #=> "A1"
239
+ # ws.rows.first.cells.first.r #=> "A1"
240
+ # @note this will be discontinued in 1.1.0 - prefer Axlsx.cell_r
197
241
  def r
198
- "#{col_ref}#{@row.index+1}"
242
+ "#{Axlsx::col_ref(index)}#{@row.index+1}"
199
243
  end
200
244
 
201
245
  # @return [String] The absolute alpha(column)numeric(row) reference for this sell.
202
246
  # @example Absolute Cell Reference
203
- # ws.rows.first.cells.first.r #=> "$A$1"
247
+ # ws.rows.first.cells.first.r #=> "$A$1"
204
248
  def r_abs
205
- "$#{r.split('').join('$')}"
249
+ "$#{r.match(%r{([A-Z]+)([0-9]+)})[1,2].join('$')}"
206
250
  end
207
251
 
208
252
  # @return [Integer] The cellXfs item index applied to this cell.
@@ -229,97 +273,102 @@ module Axlsx
229
273
  target.r
230
274
  end
231
275
  self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
232
- end
276
+ end
277
+
278
+ # builds an xml text run based on this cells attributes.
279
+ # @param [String] str The string instance this run will be concated to.
280
+ # @return [String]
281
+ def run_xml_string(str = '')
282
+ if is_text_run?
283
+ data = self.instance_values.reject{|key, value| value == nil }
284
+ keys = data.keys & INLINE_STYLES
285
+ keys.delete ['value', 'type']
286
+ str << "<r><rPr>"
287
+ keys.each do |key|
288
+ case key
289
+ when 'font_name'
290
+ str << "<rFont val='"<< @font_name << "'/>"
291
+ when 'color'
292
+ str << data[key].to_xml_string
293
+ else
294
+ "<" << key.to_s << " val='" << data[key].to_s << "'/>"
295
+ end
296
+ end
297
+ str << "</rPr>" << "<t>" << value.to_s << "</t></r>"
298
+ else
299
+ str << "<t>" << value.to_s << "</t>"
300
+ end
301
+ str
302
+ end
233
303
 
234
304
  # Serializes the cell
235
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
305
+ # @param [Integer] r_index The row index for the cell
306
+ # @param [Integer] c_index The cell index in the row.
307
+ # @param [String] str The string index the cell content will be appended to. Defaults to empty string.
236
308
  # @return [String] xml text for the cell
237
- # @note
238
- # Shared Strings are not used in this library. All values are set directly in the each sheet.
239
- def to_xml(xml)
240
-
241
- # however nokogiri does a nice 'force_encoding' which we shall remove!
242
- if @type == :string
309
+ def to_xml_string(r_index, c_index, str = '')
310
+ return str if @value.nil?
311
+ str << '<c r="' << Axlsx::cell_r(c_index, r_index) << '" s="' << @style.to_s << '" '
312
+ case @type
313
+ when :string
243
314
  #parse formula
244
315
  if @value.start_with?('=')
245
- xml.c(:r => r, :t=>:str, :s=>style) {
246
- xml.f @value.to_s.gsub('=', '')
247
- }
316
+ str << 't="str"><f>' << @value.to_s.gsub('=', '') << '</f>'
248
317
  else
249
- #parse standard string
250
- #xml.c(:r => r, :t=>:inlineStr, :s=>style) {
251
- # xml.is { xml.t @value.to_s }
252
- #}
253
- #parse styled string
254
- xml.c(:r => r, :s=>style, :t => :inlineStr) {
255
- xml.is {
256
- xml.r {
257
- xml.rPr {
258
- xml.rFont(:val=>@font_name) if @font_name
259
- xml.charset(:val=>@charset) if @charset
260
- xml.family(:val=>@family) if @family
261
- xml.b(:val=>@b) if @b
262
- xml.i(:val=>@i) if @i
263
- xml.strike(:val=>@strike) if @strike
264
- xml.outline(:val=>@outline) if @outline
265
- xml.shadow(:val=>@shadow) if @shadow
266
- xml.condense(:val=>@condense) if @condense
267
- xml.extend(:val=>@extend) if @extend
268
- @color.to_xml(xml) if @color
269
- xml.sz(:val=>@sz) if @sz
270
- xml.u(:val=>@u) if @u
271
- # :baseline, :subscript, :superscript
272
- xml.vertAlign(:val=>@vertAlign) if @verAlign
273
- # :none, major, :minor
274
- xml.scheme(:val=>@scheme) if @scheme
275
- }
276
- xml.t @value.to_s
277
- }
278
- }
279
- }
318
+ #parse shared
319
+ if @ssti
320
+ str << 't="s"><v>' << @ssti.to_s << '</v>'
321
+ else
322
+ str << 't="inlineStr"><is>' << run_xml_string << '</is>'
323
+ end
280
324
  end
281
- elsif @type == :time
282
- # Using hardcoded offsets here as some operating systems will not except a 'negative' offset from the ruby epoc.
283
- # (1970)
284
- epoc1900 = -2209021200 #Time.local(1900, 1, 1)
285
- epoc1904 = -2082877200 #Time.local(1904, 1, 1)
286
- epoc = Workbook.date1904 ? epoc1904 : epoc1900
287
- v = ((@value.localtime.to_f - epoc) /60.0/60.0/24.0).to_f
288
- xml.c(:r => r, :s => style) { xml.v v }
325
+ when :date
326
+ # TODO: See if this is subject to the same restriction as Time below
327
+ str << '><v>' << DateTimeConverter::date_to_serial(@value).to_s << '</v>'
328
+ when :time
329
+ str << '><v>' << DateTimeConverter::time_to_serial(@value).to_s << '</v>'
330
+ when :boolean
331
+ str << 't="b"><v>' << @value.to_s << '</v>'
289
332
  else
290
- xml.c(:r => r, :s => style) { xml.v value }
333
+ str << '><v>' << @value.to_s << '</v>'
291
334
  end
335
+ str << '</c>'
292
336
  end
293
337
 
338
+ private
339
+
340
+ # Utility method for setting inline style attributes
341
+ def set_run_style( validator, attr, value)
342
+ return unless INLINE_STYLES.include?(attr.to_s)
343
+ Axlsx.send(validator, value) unless validator == nil
344
+ self.instance_variable_set :"@#{attr.to_s}", value
345
+ @is_text_run = true
346
+ end
294
347
 
295
- private
348
+ # @see ssti
349
+ def ssti=(v)
350
+ Axlsx::validate_unsigned_int(v)
351
+ @ssti = v
352
+ end
296
353
 
297
354
  # assigns the owning row for this cell.
298
355
  def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
299
-
300
- # converts the column index into alphabetical values.
301
- # @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
302
- # @return [String]
303
- def col_ref
304
- chars = []
305
- index = self.index
306
- while index >= 26 do
307
- chars << ((index % 26) + 65).chr
308
- index /= 26
309
- end
310
- chars << ((chars.empty? ? index : index-1) + 65).chr
311
- chars.reverse.join
312
- end
313
356
 
314
- # Determines the cell type based on the cell value.
357
+ # Determines the cell type based on the cell value.
315
358
  # @note This is only used when a cell is created but no :type option is specified, the following rules apply:
316
- # 1. If the value is an instance of Time, the type is set to :time
317
- # 2. :float and :integer types are determined by regular expression matching.
318
- # 3. Anything that does not meet either of the above is determined to be :string.
359
+ # 1. If the value is an instance of Date, the type is set to :date
360
+ # 2. If the value is an instance of Time, the type is set to :time
361
+ # 3. If the value is an instance of TrueClass or FalseClass, the type is set to :boolean
362
+ # 4. :float and :integer types are determined by regular expression matching.
363
+ # 5. Anything that does not meet either of the above is determined to be :string.
319
364
  # @return [Symbol] The determined type
320
- def cell_type_from_value(v)
321
- if v.is_a? Time
365
+ def cell_type_from_value(v)
366
+ if v.is_a?(Date)
367
+ :date
368
+ elsif v.is_a?(Time)
322
369
  :time
370
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
371
+ :boolean
323
372
  elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
324
373
  :integer
325
374
  elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
@@ -329,22 +378,28 @@ module Axlsx
329
378
  end
330
379
  end
331
380
 
332
- # Cast the value into this cells data type.
333
- # @note
381
+ # Cast the value into this cells data type.
382
+ # @note
334
383
  # 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.
335
384
  # @see Axlsx#date1904
336
385
  def cast_value(v)
337
- if (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
386
+ return nil if v.nil?
387
+ if @type == :date
388
+ self.style = STYLE_DATE if self.style == 0
389
+ v
390
+ elsif (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
338
391
  self.style = STYLE_DATE if self.style == 0
339
392
  v.respond_to?(:to_time) ? v.to_time : v
340
393
  elsif @type == :float
341
394
  v.to_f
342
395
  elsif @type == :integer
343
396
  v.to_i
397
+ elsif @type == :boolean
398
+ v ? 1 : 0
344
399
  else
345
400
  @type = :string
346
- v.to_s
401
+ ::CGI.escapeHTML(v.to_s)
347
402
  end
348
- end
403
+ end
349
404
  end
350
405
  end
@@ -0,0 +1,114 @@
1
+ # encoding: UTF-8
2
+ module Axlsx
3
+
4
+ # The Col class defines column attributes for columns in sheets.
5
+ class Col
6
+
7
+ # First column affected by this 'column info' record.
8
+ # @return [Integer]
9
+ attr_reader :min
10
+
11
+ # Last column affected by this 'column info' record.
12
+ # @return [Integer]
13
+ attr_reader :max
14
+
15
+ # Flag indicating if the specified column(s) is set to 'best fit'. 'Best fit' is set to true under these conditions:
16
+ # The column width has never been manually set by the user, AND The column width is not the default width
17
+ # 'Best fit' means that when numbers are typed into a cell contained in a 'best fit' column, the column width should
18
+ # automatically resize to display the number. [Note: In best fit cases, column width must not be made smaller, only larger. end note]
19
+ # @return [Boolean]
20
+ attr_reader :bestFit
21
+
22
+ # Flag indicating if the outlining of the affected column(s) is in the collapsed state.
23
+ # @return [Boolean]
24
+ attr_reader :collapsed
25
+
26
+ # Flag indicating if the affected column(s) are hidden on this worksheet.
27
+ # @return [Boolean]
28
+ attr_reader :hidden
29
+
30
+ # Outline level of affected column(s). Range is 0 to 7.
31
+ # @return [Integer]
32
+ attr_reader :outlineLevel
33
+
34
+ # Flag indicating if the phonetic information should be displayed by default for the affected column(s) of the worksheet.
35
+ # @return [Boolean]
36
+ attr_reader :phonetic
37
+
38
+ # Default style for the affected column(s). Affects cells not yet allocated in the column(s). In other words, this style applies to new columns.
39
+ # @return [Integer]
40
+ attr_reader :style
41
+
42
+ # The width of the column
43
+ # @return [Numeric]
44
+ attr_reader :width
45
+
46
+ # @return [Boolean]
47
+ attr_reader :customWidth
48
+
49
+ # @see Col#collapsed
50
+ def collapsed=(v)
51
+ Axlsx.validate_boolean(v)
52
+ @collapsed = v
53
+ end
54
+
55
+ # @see Col#hidden
56
+ def hidden=(v)
57
+ Axlsx.validate_boolean(v)
58
+ @hidden = v
59
+ end
60
+
61
+ # @see Col#outline
62
+ def outlineLevel=(v)
63
+ Axlsx.validate_boolean(v)
64
+ @outlineLevel = v
65
+ end
66
+
67
+ # @see Col#phonetic
68
+ def phonetic=(v)
69
+ Axlsx.validate_boolean(v)
70
+ @phonetic = v
71
+ end
72
+
73
+ # @see Col#style
74
+ def style=(v)
75
+ Axlsx.validate_unsigned_int(v)
76
+ @style = v
77
+ end
78
+
79
+ # @see Col#width
80
+ def width=(v)
81
+ Axlsx.validate_unsigned_numeric(v) unless v == nil
82
+ @customWidth = @bestFit = v != nil
83
+ @width = v
84
+ end
85
+
86
+ # Create a new Col objects
87
+ # @param min First column affected by this 'column info' record.
88
+ # @param max Last column affected by this 'column info' record.
89
+ # @option options [Boolean] collapsed see Col#collapsed
90
+ # @option options [Boolean] hidden see Col#hidden
91
+ # @option options [Boolean] outlineLevel see Col#outlineLevel
92
+ # @option options [Boolean] phonetic see Col#phonetic
93
+ # @option options [Integer] style see Col#style
94
+ # @option options [Numeric] width see Col#width
95
+ def initialize(min, max, options={})
96
+ Axlsx.validate_unsigned_int(max)
97
+ Axlsx.validate_unsigned_int(min)
98
+ @min = min
99
+ @max = max
100
+ options.each do |o|
101
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
102
+ end
103
+ end
104
+
105
+ # Serialize this columns data to an xml string
106
+ # @param [String] str
107
+ # @return [String]
108
+ def to_xml_string(str = '')
109
+ attrs = self.instance_values.reject{ |key, value| value == nil }
110
+ str << '<col ' << attrs.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ') << '/>'
111
+ end
112
+
113
+ end
114
+ end
File without changes
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ require "date"
3
+
4
+ module Axlsx
5
+ # The DateTimeConverter class converts both data and time types to their apprpriate excel serializations
6
+ class DateTimeConverter
7
+
8
+ # The date_to_serial method converts Date objects to the equivelant excel serialized forms
9
+ # @param [Date] date the date to be serialized
10
+ # @return [Numeric]
11
+ def self.date_to_serial(date)
12
+ epoch = Axlsx::Workbook::date1904 ? Date.new(1904) : Date.new(1899, 12, 30)
13
+ (date-epoch).to_f
14
+ end
15
+
16
+ # The time_to_serial methond converts a Time object its excel serialized form.
17
+ # @param [Time] time the time to be serialized
18
+ # @return [Numeric]
19
+ def self.time_to_serial(time)
20
+ # Using hardcoded offsets here as some operating systems will not except
21
+ # a 'negative' offset from the ruby epoch.
22
+ epoch1900 = -2209161600 # Time.utc(1899, 12, 30).to_i
23
+ epoch1904 = -2082844800 # Time.utc(1904, 1, 1).to_i
24
+ seconds_per_day = 86400 # 60*60*24
25
+ epoch = Axlsx::Workbook::date1904 ? epoch1904 : epoch1900
26
+ (time.to_f - epoch)/seconds_per_day
27
+ end
28
+ end
29
+ end