axlsx 1.0.17 → 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 (167) hide show
  1. data/CHANGELOG.md +11 -3
  2. data/README.md +159 -51
  3. data/examples/example.csv +1000 -0
  4. data/examples/example.rb +255 -150
  5. data/examples/example.xlsx +0 -0
  6. data/examples/example_streamed.xlsx +0 -0
  7. data/examples/no-use_autowidth.xlsx +0 -0
  8. data/examples/shared_strings_example.xlsx +0 -0
  9. data/lib/axlsx/content_type/content_type.rb +12 -12
  10. data/lib/axlsx/content_type/default.rb +9 -6
  11. data/lib/axlsx/content_type/override.rb +12 -8
  12. data/lib/axlsx/doc_props/app.rb +37 -40
  13. data/lib/axlsx/doc_props/core.rb +12 -17
  14. data/lib/axlsx/drawing/axis.rb +38 -19
  15. data/lib/axlsx/drawing/bar_3D_chart.rb +33 -32
  16. data/lib/axlsx/drawing/bar_series.rb +13 -14
  17. data/lib/axlsx/drawing/cat_axis.rb +15 -14
  18. data/lib/axlsx/drawing/cat_axis_data.rb +16 -18
  19. data/lib/axlsx/drawing/chart.rb +39 -40
  20. data/lib/axlsx/drawing/drawing.rb +15 -12
  21. data/lib/axlsx/drawing/graphic_frame.rb +21 -21
  22. data/lib/axlsx/drawing/hyperlink.rb +12 -11
  23. data/lib/axlsx/drawing/line_3D_chart.rb +30 -28
  24. data/lib/axlsx/drawing/line_series.rb +11 -11
  25. data/lib/axlsx/drawing/marker.rb +10 -8
  26. data/lib/axlsx/drawing/named_axis_data.rb +36 -0
  27. data/lib/axlsx/drawing/one_cell_anchor.rb +17 -16
  28. data/lib/axlsx/drawing/pic.rb +25 -37
  29. data/lib/axlsx/drawing/picture_locking.rb +21 -18
  30. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -8
  31. data/lib/axlsx/drawing/pie_series.rb +15 -12
  32. data/lib/axlsx/drawing/scaling.rb +10 -10
  33. data/lib/axlsx/drawing/scatter_chart.rb +69 -0
  34. data/lib/axlsx/drawing/scatter_series.rb +39 -0
  35. data/lib/axlsx/drawing/ser_axis.rb +10 -10
  36. data/lib/axlsx/drawing/series.rb +15 -15
  37. data/lib/axlsx/drawing/series_title.rb +14 -14
  38. data/lib/axlsx/drawing/title.rb +26 -26
  39. data/lib/axlsx/drawing/two_cell_anchor.rb +18 -20
  40. data/lib/axlsx/drawing/val_axis.rb +8 -7
  41. data/lib/axlsx/drawing/val_axis_data.rb +17 -17
  42. data/lib/axlsx/drawing/view_3D.rb +22 -20
  43. data/lib/axlsx/package.rb +60 -43
  44. data/lib/axlsx/rels/relationship.rb +11 -8
  45. data/lib/axlsx/rels/relationships.rb +7 -1
  46. data/lib/axlsx/stylesheet/#num_fmt.rb# +69 -0
  47. data/lib/axlsx/stylesheet/border.rb +27 -23
  48. data/lib/axlsx/stylesheet/border_pr.rb +16 -15
  49. data/lib/axlsx/stylesheet/cell_alignment.rb +23 -21
  50. data/lib/axlsx/stylesheet/cell_protection.rb +10 -7
  51. data/lib/axlsx/stylesheet/cell_style.rb +8 -5
  52. data/lib/axlsx/stylesheet/color.rb +20 -14
  53. data/lib/axlsx/stylesheet/fill.rb +7 -5
  54. data/lib/axlsx/stylesheet/font.rb +21 -14
  55. data/lib/axlsx/stylesheet/gradient_fill.rb +19 -16
  56. data/lib/axlsx/stylesheet/gradient_stop.rb +9 -5
  57. data/lib/axlsx/stylesheet/num_fmt.rb +12 -6
  58. data/lib/axlsx/stylesheet/pattern_fill.rb +25 -10
  59. data/lib/axlsx/stylesheet/styles.rb +47 -35
  60. data/lib/axlsx/stylesheet/table_style.rb +9 -4
  61. data/lib/axlsx/stylesheet/table_style_element.rb +10 -7
  62. data/lib/axlsx/stylesheet/table_styles.rb +11 -8
  63. data/lib/axlsx/stylesheet/xf.rb +29 -25
  64. data/lib/axlsx/util/constants.rb +20 -14
  65. data/lib/axlsx/util/simple_typed_list.rb +18 -9
  66. data/lib/axlsx/util/validators.rb +13 -6
  67. data/lib/axlsx/version.rb +1 -1
  68. data/lib/axlsx/workbook/shared_strings_table.rb +19 -21
  69. data/lib/axlsx/workbook/workbook.rb +58 -34
  70. data/lib/axlsx/workbook/worksheet/cell.rb +149 -132
  71. data/lib/axlsx/workbook/worksheet/col.rb +114 -0
  72. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  73. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +29 -0
  74. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -0
  75. data/lib/axlsx/workbook/worksheet/row.rb +40 -23
  76. data/lib/axlsx/workbook/worksheet/table.rb +96 -0
  77. data/lib/axlsx/workbook/worksheet/table.rb~ +97 -0
  78. data/lib/axlsx/workbook/worksheet/worksheet.rb +243 -127
  79. data/lib/axlsx.rb +30 -9
  80. data/lib/schema/dc.xsd +5 -5
  81. data/lib/schema/dcmitype.xsd +5 -3
  82. data/lib/schema/dcterms.xsd +15 -15
  83. data/lib/schema/opc-coreProperties.xsd +6 -2
  84. data/lib/schema/xml.xsd +7 -8
  85. data/test/#benchmark.txt# +7 -0
  86. data/test/#tc_helper.rb# +3 -0
  87. data/test/benchmark.rb +81 -0
  88. data/test/benchmark.rb~ +0 -0
  89. data/test/benchmark.txt +6 -0
  90. data/test/benchmark.txt~ +6 -0
  91. data/test/content_type/tc_content_type.rb +30 -32
  92. data/test/content_type/tc_default.rb +8 -23
  93. data/test/content_type/tc_override.rb +7 -21
  94. data/test/doc_props/tc_app.rb +2 -8
  95. data/test/doc_props/tc_core.rb +6 -7
  96. data/test/drawing/tc_axis.rb +7 -3
  97. data/test/drawing/tc_bar_3D_chart.rb +6 -7
  98. data/test/drawing/tc_bar_series.rb +4 -5
  99. data/test/drawing/tc_cat_axis.rb +2 -3
  100. data/test/drawing/tc_cat_axis_data.rb +2 -3
  101. data/test/drawing/tc_chart.rb +13 -14
  102. data/test/drawing/tc_drawing.rb +7 -8
  103. data/test/drawing/tc_graphic_frame.rb +3 -4
  104. data/test/drawing/tc_hyperlink.rb +2 -3
  105. data/test/drawing/tc_line_3d_chart.rb +5 -6
  106. data/test/drawing/tc_line_series.rb +3 -4
  107. data/test/drawing/tc_marker.rb +3 -4
  108. data/test/drawing/tc_one_cell_anchor.rb +6 -7
  109. data/test/drawing/tc_pic.rb +8 -9
  110. data/test/drawing/tc_picture_locking.rb +2 -3
  111. data/test/drawing/tc_pie_3D_chart.rb +5 -6
  112. data/test/drawing/tc_pie_series.rb +4 -5
  113. data/test/drawing/tc_scaling.rb +3 -4
  114. data/test/drawing/tc_scatter_chart.rb +43 -0
  115. data/test/drawing/tc_scatter_series.rb +20 -0
  116. data/test/drawing/tc_ser_axis.rb +2 -3
  117. data/test/drawing/tc_series.rb +4 -5
  118. data/test/drawing/tc_series_title.rb +4 -5
  119. data/test/drawing/tc_title.rb +4 -5
  120. data/test/drawing/tc_two_cell_anchor.rb +4 -5
  121. data/test/drawing/tc_val_axis.rb +2 -3
  122. data/test/drawing/tc_val_axis_data.rb +2 -3
  123. data/test/drawing/tc_view_3D.rb +6 -7
  124. data/test/example.csv +1000 -0
  125. data/test/example.xlsx +0 -0
  126. data/test/example_streamed.xlsx +0 -0
  127. data/test/profile.rb +33 -0
  128. data/test/rels/tc_relationship.rb +5 -6
  129. data/test/rels/tc_relationships.rb +4 -5
  130. data/test/stylesheet/tc_border.rb +3 -4
  131. data/test/stylesheet/tc_border_pr.rb +3 -4
  132. data/test/stylesheet/tc_cell_alignment.rb +10 -6
  133. data/test/stylesheet/tc_cell_protection.rb +2 -3
  134. data/test/stylesheet/tc_cell_style.rb +2 -3
  135. data/test/stylesheet/tc_color.rb +2 -3
  136. data/test/stylesheet/tc_fill.rb +1 -2
  137. data/test/stylesheet/tc_font.rb +12 -5
  138. data/test/stylesheet/tc_gradient_fill.rb +1 -2
  139. data/test/stylesheet/tc_gradient_stop.rb +1 -2
  140. data/test/stylesheet/tc_num_fmt.rb +1 -2
  141. data/test/stylesheet/tc_pattern_fill.rb +3 -4
  142. data/test/stylesheet/tc_styles.rb +16 -6
  143. data/test/stylesheet/tc_table_style.rb +2 -3
  144. data/test/stylesheet/tc_table_style_element.rb +2 -3
  145. data/test/stylesheet/tc_table_styles.rb +3 -4
  146. data/test/stylesheet/tc_xf.rb +16 -17
  147. data/test/tc_axlsx.rb +39 -0
  148. data/test/tc_axlsx.rb~ +0 -0
  149. data/test/tc_helper.rb +3 -0
  150. data/test/tc_helper.rb~ +3 -0
  151. data/test/tc_package.rb +13 -10
  152. data/test/util/tc_simple_typed_list.rb +8 -9
  153. data/test/util/tc_validators.rb +7 -8
  154. data/test/workbook/tc_shared_strings_table.rb +5 -6
  155. data/test/workbook/tc_workbook.rb +24 -6
  156. data/test/workbook/worksheet/table/tc_table.rb +71 -0
  157. data/test/workbook/worksheet/table/tc_table.rb~ +72 -0
  158. data/test/workbook/worksheet/tc_cell.rb +62 -18
  159. data/test/workbook/worksheet/tc_col.rb +59 -0
  160. data/test/workbook/worksheet/tc_col.rb~ +10 -0
  161. data/test/workbook/worksheet/tc_date_time_converter.rb +126 -0
  162. data/test/workbook/worksheet/tc_page_margins.rb +97 -0
  163. data/test/workbook/worksheet/tc_row.rb +54 -4
  164. data/test/workbook/worksheet/tc_worksheet.rb +177 -34
  165. metadata +69 -41
  166. data/test/drawing/tc_hyperlink.rb~ +0 -71
  167. data/test/workbook/tc_shared_strings_table.rb~ +0 -8
@@ -1,61 +1,66 @@
1
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
 
26
27
 
27
28
  # An array of available inline styes.
28
- INLINE_STYLES = ['value', 'type', 'font_name', 'charset',
29
- 'family', 'b', 'i', 'strike','outline',
30
- 'shadow', 'condense', 'extend', 'u',
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',
31
37
  'vertAlign', 'sz', 'color', 'scheme']
32
38
 
33
-
34
39
  # The index of the cellXfs item to be applied to this cell.
35
- # @return [Integer]
40
+ # @return [Integer]
36
41
  # @see Axlsx::Styles
37
42
  attr_reader :style
38
43
 
39
44
  # The row this cell belongs to.
40
45
  # @return [Row]
41
46
  attr_reader :row
42
-
43
- # The cell's data type. Currently only four types are supported, :time, :float, :integer and :string.
44
- # 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
45
50
  # automatically determed.
46
51
  # @see Cell#cell_type_from_value
47
- # @return [Symbol] The type of data this cell's value is cast to.
48
- # @raise [ArgumentExeption] Cell.type must be one of [:time, :float, :integer, :string]
49
- # @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
50
55
  # If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
51
- # :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
52
57
  # :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
53
58
  # No support is currently implemented for parsing time strings.
54
59
  attr_reader :type
55
60
  # @see type
56
- def type=(v)
57
- RestrictionValidator.validate "Cell.type", [:time, :float, :integer, :string], v
58
- @type=v
61
+ def type=(v)
62
+ RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean], v
63
+ @type=v
59
64
  self.value = @value unless @value.nil?
60
65
  end
61
66
 
@@ -68,103 +73,118 @@ module Axlsx
68
73
  #TODO: consider doing value based type determination first?
69
74
  @value = cast_value(v)
70
75
  end
71
-
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
+
72
85
  # The inline font_name property for the cell
73
86
  # @return [String]
74
87
  attr_reader :font_name
75
88
  # @see font_name
76
- 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
77
90
 
78
91
  # The inline charset property for the cell
79
92
  # @return [String]
80
93
  attr_reader :charset
81
94
  # @see charset
82
- def charset=(v) Axlsx::validate_unsigned_int(v); @charset = v; end
95
+ def charset=(v) set_run_style :validate_unsigned_int, :charset, v; end
83
96
 
84
97
  # The inline family property for the cell
85
98
  # @return [String]
86
99
  attr_reader :family
87
100
  # @see family
88
- def family=(v) Axlsx::validate_string(v); @family = v; end
101
+ def family=(v) set_run_style :validate_string, :family, v; end
89
102
 
90
103
  # The inline bold property for the cell
91
104
  # @return [Boolean]
92
105
  attr_reader :b
93
106
  # @see b
94
- def b=(v) Axlsx::validate_boolean(v); @b = v; end
107
+ def b=(v) set_run_style :validate_boolean, :b, v; end
95
108
 
96
109
  # The inline italic property for the cell
97
110
  # @return [Boolean]
98
111
  attr_reader :i
99
112
  # @see i
100
- def i=(v) Axlsx::validate_boolean(v); @i = v; end
113
+ def i=(v) set_run_style :validate_boolean, :i, v; end
101
114
 
102
115
  # The inline strike property for the cell
103
116
  # @return [Boolean]
104
117
  attr_reader :strike
105
118
  # @see strike
106
- def strike=(v) Axlsx::validate_boolean(v); @strike = v; end
119
+ def strike=(v) set_run_style :validate_boolean, :strike, v; end
107
120
 
108
121
  # The inline outline property for the cell
109
122
  # @return [Boolean]
110
123
  attr_reader :outline
111
124
  # @see outline
112
- def outline=(v) Axlsx::validate_boolean(v); @outline = v; end
125
+ def outline=(v) set_run_style :validate_boolean, :outline, v; end
113
126
 
114
127
  # The inline shadow property for the cell
115
128
  # @return [Boolean]
116
129
  attr_reader :shadow
117
130
  # @see shadow
118
- def shadow=(v) Axlsx::validate_boolean(v); @shadow = v; end
131
+ def shadow=(v) set_run_style :validate_boolean, :shadow, v; end
119
132
 
120
133
  # The inline condense property for the cell
121
134
  # @return [Boolean]
122
135
  attr_reader :condense
123
136
  # @see condense
124
- def condense=(v) Axlsx::validate_boolean(v); @condense = v; end
137
+ def condense=(v) set_run_style :validate_boolean, :condense, v; end
125
138
 
126
139
  # The inline extend property for the cell
127
140
  # @return [Boolean]
128
141
  attr_reader :extend
129
142
  # @see extend
130
- def extend=(v) Axlsx::validate_boolean(v); @extend = v; end
143
+ def extend=(v) set_run_style :validate_boolean, :extend, v; end
131
144
 
132
145
  # The inline underline property for the cell
133
146
  # @return [Boolean]
134
147
  attr_reader :u
135
148
  # @see u
136
- def u=(v) Axlsx::validate_boolean(v); @u = v; end
149
+ def u=(v) set_run_style :validate_boolean, :u, v; end
137
150
 
138
151
  # The inline color property for the cell
139
152
  # @return [Color]
140
153
  attr_reader :color
141
154
  # @param [String] The 8 character representation for an rgb color #FFFFFFFF"
142
- def color=(v)
155
+ def color=(v)
143
156
  @color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
157
+ @has_run_style = true
144
158
  end
145
159
 
146
160
  # The inline sz property for the cell
147
161
  # @return [Boolean]
148
162
  attr_reader :sz
149
163
  # @see sz
150
- def sz=(v) Axlsx::validate_unsigned_int(v); @sz = v; end
164
+ def sz=(v) set_run_style :validate_unsigned_int, :sz, v; end
151
165
 
152
166
  # The inline vertical alignment property for the cell
153
167
  # this must be one of [:baseline, :subscript, :superscript]
154
168
  # @return [Symbol]
155
169
  attr_reader :vertAlign
156
170
  # @see vertAlign
157
- 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
158
175
 
159
176
  # The inline scheme property for the cell
160
177
  # this must be one of [:none, major, minor]
161
178
  # @return [Symbol]
162
179
  attr_reader :scheme
163
180
  # @see scheme
164
- 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
165
185
 
166
186
  # @param [Row] row The row this cell belongs to.
167
- # @param [Any] value The value associated with this cell.
187
+ # @param [Any] value The value associated with this cell.
168
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.
169
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.
170
190
  # @option options [String] font_name
@@ -183,9 +203,11 @@ module Axlsx
183
203
  # @option options [String] color an 8 letter rgb specification
184
204
  # @option options [Symbol] scheme must be one of :none, major, :minor
185
205
  def initialize(row, value="", options={})
186
- 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
187
209
  @styles = row.worksheet.workbook.styles
188
- @row.cells << self
210
+ @row.cells << self
189
211
  options.each do |o|
190
212
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
191
213
  end
@@ -197,19 +219,14 @@ module Axlsx
197
219
  # The Shared Strings Table index for this cell
198
220
  # @return [Integer]
199
221
  attr_reader :ssti
200
-
222
+
201
223
  # equality comparison to test value, type and inline style attributes
202
224
  # this is how we work out if the cell needs to be added or already exists in the shared strings table
203
- def shareable(v)
204
-
205
- #using reject becase 1.8.7 select returns an array...
206
- v_hash = v.instance_values.reject { |k, v| !INLINE_STYLES.include?(k) }
207
- self_hash = self.instance_values.reject { |k, v| !INLINE_STYLES.include?(k) }
208
- # required as color is an object, and the comparison will fail even though both use the same color.
209
- v_hash['color'] = v_hash['color'].instance_values if v_hash['color']
225
+ def shareable_hash
226
+ self_hash = {}
227
+ INLINE_STYLES.each { |style| self_hash[style] = self.instance_variable_get("@" + style) }
210
228
  self_hash['color'] = self_hash['color'].instance_values if self_hash['color']
211
-
212
- v_hash == self_hash
229
+ self_hash
213
230
  end
214
231
 
215
232
  # @return [Integer] The index of the cell in the containing row.
@@ -219,16 +236,17 @@ module Axlsx
219
236
 
220
237
  # @return [String] The alpha(column)numeric(row) reference for this sell.
221
238
  # @example Relative Cell Reference
222
- # 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
223
241
  def r
224
- "#{col_ref}#{@row.index+1}"
242
+ "#{Axlsx::col_ref(index)}#{@row.index+1}"
225
243
  end
226
244
 
227
245
  # @return [String] The absolute alpha(column)numeric(row) reference for this sell.
228
246
  # @example Absolute Cell Reference
229
- # ws.rows.first.cells.first.r #=> "$A$1"
247
+ # ws.rows.first.cells.first.r #=> "$A$1"
230
248
  def r_abs
231
- "$#{r.split('').join('$')}"
249
+ "$#{r.match(%r{([A-Z]+)([0-9]+)})[1,2].join('$')}"
232
250
  end
233
251
 
234
252
  # @return [Integer] The cellXfs item index applied to this cell.
@@ -255,109 +273,102 @@ module Axlsx
255
273
  target.r
256
274
  end
257
275
  self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
258
- end
259
-
260
- # builds an xml text run based on this cells attributes. This is extracted from to_xml so that shared strings can use it.
261
- # @param [Nokogiri::XML::Builder] xml The document builder instance this output will be added to.
262
- # @return [String] the xml for this cell's text run
263
- def run_xml(xml)
264
- if (self.instance_values.keys & INLINE_STYLES).size > 0
265
- xml.r {
266
- xml.rPr {
267
- xml.rFont(:val=>@font_name) if @font_name
268
- xml.charset(:val=>@charset) if @charset
269
- xml.family(:val=>@family) if @family
270
- xml.b(:val=>@b) if @b
271
- xml.i(:val=>@i) if @i
272
- xml.strike(:val=>@strike) if @strike
273
- xml.outline(:val=>@outline) if @outline
274
- xml.shadow(:val=>@shadow) if @shadow
275
- xml.condense(:val=>@condense) if @condense
276
- xml.extend(:val=>@extend) if @extend
277
- @color.to_xml(xml) if @color
278
- xml.sz(:val=>@sz) if @sz
279
- xml.u(:val=>@u) if @u
280
- # :baseline, :subscript, :superscript
281
- xml.vertAlign(:val=>@vertAlign) if @verAlign
282
- # :none, major, :minor
283
- xml.scheme(:val=>@scheme) if @scheme
284
- }
285
- xml.t @value.to_s
286
- }
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>"
287
298
  else
288
- xml.t @value.to_s
289
- end
299
+ str << "<t>" << value.to_s << "</t>"
300
+ end
301
+ str
290
302
  end
291
303
 
292
304
  # Serializes the cell
293
- # @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.
294
308
  # @return [String] xml text for the cell
295
- def to_xml(xml)
296
- 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
297
314
  #parse formula
298
315
  if @value.start_with?('=')
299
- xml.c(:r => r, :t=>:str, :s=>style) {
300
- xml.f @value.to_s.gsub('=', '')
301
- }
316
+ str << 't="str"><f>' << @value.to_s.gsub('=', '') << '</f>'
302
317
  else
303
318
  #parse shared
304
319
  if @ssti
305
- xml.c(:r => r, :s=>style, :t => :s) { xml.v ssti }
320
+ str << 't="s"><v>' << @ssti.to_s << '</v>'
306
321
  else
307
- #parse inline string
308
- xml.c(:r => r, :s=>style, :t => :inlineStr) {
309
- xml.is {
310
- run_xml(xml)
311
- }
312
- }
322
+ str << 't="inlineStr"><is>' << run_xml_string << '</is>'
313
323
  end
314
324
  end
315
- elsif @type == :time
316
- # Using hardcoded offsets here as some operating systems will not except a 'negative' offset from the ruby epoc.
317
- epoc1900 = -2209021200 #Time.local(1900, 1, 1)
318
- epoc1904 = -2082877200 #Time.local(1904, 1, 1)
319
- epoc = Workbook.date1904 ? epoc1904 : epoc1900
320
- v = ((@value.localtime.to_f - epoc) /60.0/60.0/24.0).to_f
321
- 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>'
322
332
  else
323
- xml.c(:r => r, :s => style) { xml.v value }
333
+ str << '><v>' << @value.to_s << '</v>'
324
334
  end
335
+ str << '</c>'
325
336
  end
326
337
 
327
- private
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
328
347
 
329
348
  # @see ssti
330
- def ssti=(v)
349
+ def ssti=(v)
331
350
  Axlsx::validate_unsigned_int(v)
332
351
  @ssti = v
333
352
  end
334
353
 
335
354
  # assigns the owning row for this cell.
336
355
  def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
337
-
338
- # converts the column index into alphabetical values.
339
- # @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
340
- # @return [String]
341
- def col_ref
342
- chars = []
343
- index = self.index
344
- while index >= 26 do
345
- chars << ((index % 26) + 65).chr
346
- index /= 26
347
- end
348
- chars << ((chars.empty? ? index : index-1) + 65).chr
349
- chars.reverse.join
350
- end
351
356
 
352
- # Determines the cell type based on the cell value.
357
+ # Determines the cell type based on the cell value.
353
358
  # @note This is only used when a cell is created but no :type option is specified, the following rules apply:
354
- # 1. If the value is an instance of Time, the type is set to :time
355
- # 2. :float and :integer types are determined by regular expression matching.
356
- # 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.
357
364
  # @return [Symbol] The determined type
358
- def cell_type_from_value(v)
359
- 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)
360
369
  :time
370
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
371
+ :boolean
361
372
  elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
362
373
  :integer
363
374
  elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
@@ -367,22 +378,28 @@ module Axlsx
367
378
  end
368
379
  end
369
380
 
370
- # Cast the value into this cells data type.
371
- # @note
381
+ # Cast the value into this cells data type.
382
+ # @note
372
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.
373
384
  # @see Axlsx#date1904
374
385
  def cast_value(v)
375
- 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))
376
391
  self.style = STYLE_DATE if self.style == 0
377
392
  v.respond_to?(:to_time) ? v.to_time : v
378
393
  elsif @type == :float
379
394
  v.to_f
380
395
  elsif @type == :integer
381
396
  v.to_i
397
+ elsif @type == :boolean
398
+ v ? 1 : 0
382
399
  else
383
400
  @type = :string
384
- v.to_s
401
+ ::CGI.escapeHTML(v.to_s)
385
402
  end
386
- end
403
+ end
387
404
  end
388
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