axlsx 1.1.0 → 1.2.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 (214) hide show
  1. data/.yardopts +5 -2
  2. data/CHANGELOG.md +78 -0
  3. data/LICENSE +1 -1
  4. data/README.md +132 -331
  5. data/Rakefile +17 -5
  6. data/examples/basic_charts.rb +54 -0
  7. data/examples/chart_colors.rb +88 -0
  8. data/examples/conditional_formatting/example_conditional_formatting.rb +72 -0
  9. data/examples/conditional_formatting/getting_barred.rb +37 -0
  10. data/examples/conditional_formatting/hitting_the_high_notes.rb +37 -0
  11. data/examples/conditional_formatting/scaled_colors.rb +39 -0
  12. data/examples/conditional_formatting/stop_and_go.rb +37 -0
  13. data/examples/data_validation.rb +50 -0
  14. data/examples/example.rb +300 -152
  15. data/examples/example.xlsx +0 -0
  16. data/examples/example_streamed.xlsx +0 -0
  17. data/examples/extractive.pdf +0 -0
  18. data/examples/extractive.rb +45 -0
  19. data/examples/no-use_autowidth.xlsx +0 -0
  20. data/examples/sample.png +0 -0
  21. data/examples/scraping_html.rb +91 -0
  22. data/examples/shared_strings_example.xlsx +0 -0
  23. data/examples/sheet_protection.rb +10 -0
  24. data/examples/sheet_view.rb +34 -0
  25. data/examples/skydrive/real_example.rb +63 -0
  26. data/examples/two_cell_anchor_image.rb +11 -0
  27. data/lib/axlsx/content_type/content_type.rb +2 -0
  28. data/lib/axlsx/content_type/default.rb +30 -15
  29. data/lib/axlsx/content_type/override.rb +29 -14
  30. data/lib/axlsx/doc_props/app.rb +161 -104
  31. data/lib/axlsx/doc_props/core.rb +9 -5
  32. data/lib/axlsx/drawing/ax_data_source.rb +26 -0
  33. data/lib/axlsx/drawing/axis.rb +106 -35
  34. data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
  35. data/lib/axlsx/drawing/bar_series.rb +25 -7
  36. data/lib/axlsx/drawing/cat_axis.rb +50 -22
  37. data/lib/axlsx/drawing/chart.rb +69 -56
  38. data/lib/axlsx/drawing/d_lbls.rb +100 -0
  39. data/lib/axlsx/drawing/drawing.rb +28 -12
  40. data/lib/axlsx/drawing/graphic_frame.rb +2 -1
  41. data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
  42. data/lib/axlsx/drawing/line_series.rb +20 -4
  43. data/lib/axlsx/drawing/num_data.rb +52 -0
  44. data/lib/axlsx/drawing/num_data_source.rb +61 -0
  45. data/lib/axlsx/drawing/num_val.rb +32 -0
  46. data/lib/axlsx/drawing/pic.rb +44 -4
  47. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
  48. data/lib/axlsx/drawing/pie_series.rb +18 -4
  49. data/lib/axlsx/drawing/scatter_chart.rb +12 -18
  50. data/lib/axlsx/drawing/scatter_series.rb +28 -2
  51. data/lib/axlsx/drawing/ser_axis.rb +1 -1
  52. data/lib/axlsx/drawing/series.rb +1 -1
  53. data/lib/axlsx/drawing/str_data.rb +42 -0
  54. data/lib/axlsx/drawing/str_val.rb +33 -0
  55. data/lib/axlsx/drawing/title.rb +21 -9
  56. data/lib/axlsx/drawing/two_cell_anchor.rb +46 -9
  57. data/lib/axlsx/drawing/view_3D.rb +44 -31
  58. data/lib/axlsx/drawing/vml_drawing.rb +42 -0
  59. data/lib/axlsx/drawing/vml_shape.rb +125 -0
  60. data/lib/axlsx/package.rb +44 -16
  61. data/lib/axlsx/rels/relationship.rb +3 -3
  62. data/lib/axlsx/rels/relationships.rb +1 -11
  63. data/lib/axlsx/stylesheet/color.rb +0 -1
  64. data/lib/axlsx/stylesheet/dxf.rb +79 -0
  65. data/lib/axlsx/stylesheet/font.rb +2 -1
  66. data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
  67. data/lib/axlsx/stylesheet/styles.rb +143 -50
  68. data/lib/axlsx/stylesheet/table_style.rb +3 -3
  69. data/lib/axlsx/stylesheet/xf.rb +2 -0
  70. data/lib/axlsx/util/constants.rb +36 -0
  71. data/lib/axlsx/util/simple_typed_list.rb +15 -21
  72. data/lib/axlsx/util/validators.rb +122 -5
  73. data/lib/axlsx/version.rb +2 -7
  74. data/lib/axlsx/workbook/defined_name.rb +174 -0
  75. data/lib/axlsx/workbook/defined_names.rb +21 -0
  76. data/lib/axlsx/workbook/shared_strings_table.rb +12 -13
  77. data/lib/axlsx/workbook/workbook.rb +71 -13
  78. data/lib/axlsx/workbook/worksheet/auto_filter.rb +34 -0
  79. data/lib/axlsx/workbook/worksheet/cell.rb +45 -36
  80. data/lib/axlsx/workbook/worksheet/cfvo.rb +62 -0
  81. data/lib/axlsx/workbook/worksheet/col.rb +17 -1
  82. data/lib/axlsx/workbook/worksheet/color_scale.rb +76 -0
  83. data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
  84. data/lib/axlsx/workbook/worksheet/comment.rb +101 -0
  85. data/lib/axlsx/workbook/worksheet/comments.rb +85 -0
  86. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +82 -0
  87. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +216 -0
  88. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
  89. data/lib/axlsx/workbook/worksheet/data_bar.rb +97 -0
  90. data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
  91. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
  92. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
  93. data/lib/axlsx/workbook/worksheet/icon_set.rb +83 -0
  94. data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
  95. data/lib/axlsx/workbook/worksheet/page_setup.rb +113 -0
  96. data/lib/axlsx/workbook/worksheet/pane.rb +144 -0
  97. data/lib/axlsx/workbook/worksheet/print_options.rb +63 -0
  98. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  99. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
  100. data/lib/axlsx/workbook/worksheet/row.rb +69 -12
  101. data/lib/axlsx/workbook/worksheet/selection.rb +111 -0
  102. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
  103. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +24 -0
  104. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
  105. data/lib/axlsx/workbook/worksheet/sheet_view.rb +379 -0
  106. data/lib/axlsx/workbook/worksheet/table.rb +3 -3
  107. data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
  108. data/lib/axlsx/workbook/worksheet/worksheet.rb +379 -233
  109. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
  110. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
  111. data/lib/axlsx.rb +31 -16
  112. data/test/benchmark.rb +30 -38
  113. data/test/content_type/tc_content_type.rb +1 -6
  114. data/test/doc_props/tc_app.rb +31 -1
  115. data/test/doc_props/tc_core.rb +3 -1
  116. data/test/drawing/tc_axis.rb +46 -3
  117. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  118. data/test/drawing/tc_bar_series.rb +17 -13
  119. data/test/drawing/tc_cat_axis.rb +3 -3
  120. data/test/drawing/tc_cat_axis_data.rb +23 -13
  121. data/test/drawing/tc_chart.rb +29 -11
  122. data/test/drawing/tc_d_lbls.rb +47 -0
  123. data/test/drawing/tc_data_source.rb +17 -0
  124. data/test/drawing/tc_drawing.rb +11 -5
  125. data/test/drawing/tc_hyperlink.rb +4 -5
  126. data/test/drawing/tc_line_series.rb +9 -11
  127. data/test/drawing/tc_named_axis_data.rb +27 -0
  128. data/test/drawing/tc_num_data.rb +31 -0
  129. data/test/drawing/tc_num_val.rb +29 -0
  130. data/test/drawing/tc_pic.rb +22 -2
  131. data/test/drawing/tc_pie_3D_chart.rb +4 -8
  132. data/test/drawing/tc_pie_series.rb +11 -13
  133. data/test/drawing/tc_scatter_chart.rb +6 -1
  134. data/test/drawing/tc_scatter_series.rb +6 -5
  135. data/test/drawing/tc_series.rb +1 -1
  136. data/test/drawing/tc_str_data.rb +18 -0
  137. data/test/drawing/tc_str_val.rb +21 -0
  138. data/test/drawing/tc_title.rb +16 -0
  139. data/test/drawing/tc_two_cell_anchor.rb +2 -3
  140. data/test/drawing/tc_view_3D.rb +18 -18
  141. data/test/drawing/tc_vml_drawing.rb +25 -0
  142. data/test/drawing/tc_vml_shape.rb +100 -0
  143. data/test/profile.rb +2 -1
  144. data/test/rels/tc_relationship.rb +1 -0
  145. data/test/stylesheet/tc_dxf.rb +81 -0
  146. data/test/stylesheet/tc_gradient_fill.rb +8 -0
  147. data/test/stylesheet/tc_pattern_fill.rb +7 -1
  148. data/test/stylesheet/tc_styles.rb +163 -3
  149. data/test/stylesheet/tc_table_style.rb +8 -0
  150. data/test/stylesheet/tc_table_style_element.rb +10 -1
  151. data/test/tc_helper.rb +1 -0
  152. data/test/tc_package.rb +93 -17
  153. data/test/util/tc_simple_typed_list.rb +13 -0
  154. data/test/util/tc_validators.rb +95 -9
  155. data/test/workbook/tc_defined_name.rb +41 -0
  156. data/test/workbook/tc_workbook.rb +5 -3
  157. data/test/workbook/worksheet/table/tc_table.rb +3 -11
  158. data/test/workbook/worksheet/tc_cell.rb +52 -18
  159. data/test/workbook/worksheet/tc_cfvo.rb +31 -0
  160. data/test/workbook/worksheet/tc_col.rb +9 -0
  161. data/test/workbook/worksheet/tc_color_scale.rb +29 -0
  162. data/test/workbook/worksheet/tc_comment.rb +57 -0
  163. data/test/workbook/worksheet/tc_comments.rb +57 -0
  164. data/test/workbook/worksheet/tc_conditional_formatting.rb +217 -0
  165. data/test/workbook/worksheet/tc_data_bar.rb +39 -0
  166. data/test/workbook/worksheet/tc_data_validation.rb +265 -0
  167. data/test/workbook/worksheet/tc_date_time_converter.rb +11 -5
  168. data/test/workbook/worksheet/tc_icon_set.rb +45 -0
  169. data/test/workbook/worksheet/tc_page_setup.rb +138 -0
  170. data/test/workbook/worksheet/tc_pane.rb +94 -0
  171. data/test/workbook/worksheet/tc_print_options.rb +72 -0
  172. data/test/workbook/worksheet/tc_protected_range.rb +17 -0
  173. data/test/workbook/worksheet/tc_row.rb +44 -13
  174. data/test/workbook/worksheet/tc_selection.rb +94 -0
  175. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
  176. data/test/workbook/worksheet/tc_sheet_view.rb +214 -0
  177. data/test/workbook/worksheet/tc_worksheet.rb +147 -50
  178. metadata +216 -148
  179. data/examples/example.csv +0 -1000
  180. data/examples/example.rb~ +0 -112
  181. data/lib/axlsx/drawing/cat_axis_data.rb +0 -34
  182. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  183. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  184. data/lib/axlsx/drawing/named_axis_data.rb +0 -36
  185. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  186. data/lib/axlsx/drawing/val_axis_data.rb +0 -27
  187. data/lib/axlsx/stylesheet/#num_fmt.rb# +0 -69
  188. data/lib/axlsx/util/cbf.rb +0 -333
  189. data/lib/axlsx/util/cfb.rb~ +0 -201
  190. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  191. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  192. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  193. data/lib/axlsx/util/parser.rb~ +0 -6
  194. data/lib/axlsx/util/storage.rb~ +0 -0
  195. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  196. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  197. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  198. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  199. data/lib/schema/dc.xsd~ +0 -118
  200. data/lib/schema/dcterms.xsd~ +0 -331
  201. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  202. data/test/#benchmark.txt# +0 -7
  203. data/test/#tc_helper.rb# +0 -3
  204. data/test/benchmark.rb~ +0 -0
  205. data/test/benchmark.txt +0 -6
  206. data/test/benchmark.txt~ +0 -6
  207. data/test/drawing/tc_val_axis_data.rb +0 -17
  208. data/test/example.csv +0 -1000
  209. data/test/example.xlsx +0 -0
  210. data/test/example_streamed.xlsx +0 -0
  211. data/test/tc_axlsx.rb~ +0 -0
  212. data/test/tc_helper.rb~ +0 -3
  213. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  214. data/test/workbook/worksheet/tc_col.rb~ +0 -10
@@ -0,0 +1,79 @@
1
+ # encoding: UTF-8
2
+ module Axlsx
3
+ # The Dxf class defines an incremental formatting record for use in Styles. The recommended way to manage styles for your workbook is with Styles#add_style
4
+ # @see Styles#add_style
5
+ class Dxf
6
+ # The order in which the child elements is put in the XML seems to
7
+ # be important for Excel
8
+ CHILD_ELEMENTS = [:font, :numFmt, :fill, :alignment, :border, :protection]
9
+ #does not support extList (ExtensionList)
10
+
11
+ # The cell alignment for this style
12
+ # @return [CellAlignment]
13
+ # @see CellAlignment
14
+ attr_reader :alignment
15
+
16
+ # The cell protection for this style
17
+ # @return [CellProtection]
18
+ # @see CellProtection
19
+ attr_reader :protection
20
+
21
+ # the child NumFmt to be used to this style
22
+ # @return [NumFmt]
23
+ attr_reader :numFmt
24
+
25
+ # the child font to be used for this style
26
+ # @return [Font]
27
+ attr_reader :font
28
+
29
+ # the child fill to be used in this style
30
+ # @return [Fill]
31
+ attr_reader :fill
32
+
33
+ # the border to be used in this style
34
+ # @return [Border]
35
+ attr_reader :border
36
+
37
+ # Creates a new Xf object
38
+ # @option options [Border] border
39
+ # @option options [NumFmt] numFmt
40
+ # @option options [Fill] fill
41
+ # @option options [Font] font
42
+ # @option options [CellAlignment] alignment
43
+ # @option options [CellProtection] protection
44
+ def initialize(options={})
45
+ options.each do |o|
46
+ next if o[1].nil?
47
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
48
+ end
49
+ end
50
+
51
+ # @see Dxf#alignment
52
+ def alignment=(v) DataTypeValidator.validate "Dxf.alignment", CellAlignment, v; @alignment = v end
53
+ # @see protection
54
+ def protection=(v) DataTypeValidator.validate "Dxf.protection", CellProtection, v; @protection = v end
55
+ # @see numFmt
56
+ def numFmt=(v) DataTypeValidator.validate "Dxf.numFmt", NumFmt, v; @numFmt = v end
57
+ # @see font
58
+ def font=(v) DataTypeValidator.validate "Dxf.font", Font, v; @font = v end
59
+ # @see border
60
+ def border=(v) DataTypeValidator.validate "Dxf.border", Border, v; @border = v end
61
+ # @see fill
62
+ def fill=(v) DataTypeValidator.validate "Dxf.fill", Fill, v; @fill = v end
63
+
64
+ # Serializes the object
65
+ # @param [String] str
66
+ # @return [String]
67
+ def to_xml_string(str = '')
68
+ str << '<dxf>'
69
+ # Dxf elements have no attributes. All of the instance variables
70
+ # are child elements.
71
+ CHILD_ELEMENTS.each do |element|
72
+ self.send(element).to_xml_string(str) if self.send(element)
73
+ end
74
+ str << '</dxf>'
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -103,7 +103,8 @@ module Axlsx
103
103
  # @option options [Integer] sz
104
104
  def initialize(options={})
105
105
  options.each do |o|
106
- self.send("#{o[0]}=", o[1]) if self.respond_to? o[0]
106
+ next if o[1].nil?
107
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
107
108
  end
108
109
  end
109
110
  # @see name
@@ -68,7 +68,7 @@ module Axlsx
68
68
  # @param [String] str
69
69
  # @return [String]
70
70
  def to_xml_string(str = '')
71
- str << '<gradientFill'
71
+ str << '<gradientFill '
72
72
  h = self.instance_values.reject { |k,v| k.to_sym == :stop }
73
73
  str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
74
74
  str << '>'
@@ -14,6 +14,7 @@ module Axlsx
14
14
  require 'axlsx/stylesheet/table_style.rb'
15
15
  require 'axlsx/stylesheet/table_styles.rb'
16
16
  require 'axlsx/stylesheet/table_style_element.rb'
17
+ require 'axlsx/stylesheet/dxf.rb'
17
18
  require 'axlsx/stylesheet/xf.rb'
18
19
  require 'axlsx/stylesheet/cell_protection.rb'
19
20
 
@@ -132,11 +133,12 @@ module Axlsx
132
133
  # @option options [Integer] family The font family to use.
133
134
  # @option options [String] font_name The name of the font to use
134
135
  # @option options [Integer] num_fmt The number format to apply
135
- # @option options [String] format_code The formatting to apply. If this is specified, num_fmt is ignored.
136
- # @option options [Integer] border The border style to use.
136
+ # @option options [String] format_code The formatting to apply.
137
+ # @option options [Integer|Hash] border The border style to use.
137
138
  # @option options [String] bg_color The background color to apply to the cell
138
139
  # @option options [Boolean] hidden Indicates if the cell should be hidden
139
140
  # @option options [Boolean] locked Indicates if the cell should be locked
141
+ # @option options [Symbol] type What type of style is this. Options are [:dxf, :xf]. :xf is default
140
142
  # @option options [Hash] alignment A hash defining any of the attributes used in CellAlignment
141
143
  # @see CellAlignment
142
144
  #
@@ -189,65 +191,156 @@ module Axlsx
189
191
  # ws.add_row :values => ["Q4", 2000, 20], :style=>[title, currency, percent]
190
192
  # f = File.open('example_you_got_style.xlsx', 'w')
191
193
  # p.serialize(f)
194
+ #
195
+ # @example Differential styling
196
+ # # Differential styles apply on top of cell styles. Used in Conditional Formatting. Must specify :type => :dxf, and you can't use :num_fmt.
197
+ # require "rubygems" # if that is your preferred way to manage gems!
198
+ # require "axlsx"
199
+ #
200
+ # p = Axlsx::Package.new
201
+ # wb = p.workbook
202
+ # ws = wb.add_worksheet
203
+ #
204
+ # # define your styles
205
+ # profitable = wb.styles.add_style(:bg_color => "FFFF0000",
206
+ # :fg_color=>"#FF000000",
207
+ # :type => :dxf)
208
+ #
209
+ # ws.add_row :values => ["Genreated At:", Time.now], :styles=>[nil, date_time]
210
+ # ws.add_row :values => ["Previous Year Quarterly Profits (JPY)"], :style=>title
211
+ # ws.add_row :values => ["Quarter", "Profit", "% of Total"], :style=>title
212
+ # ws.add_row :values => ["Q1", 4000, 40], :style=>[title, currency, percent]
213
+ # ws.add_row :values => ["Q2", 3000, 30], :style=>[title, currency, percent]
214
+ # ws.add_row :values => ["Q3", 1000, 10], :style=>[title, currency, percent]
215
+ # ws.add_row :values => ["Q4", 2000, 20], :style=>[title, currency, percent]
216
+ #
217
+ # ws.add_conditional_formatting("A1:A7", { :type => :cellIs, :operator => :greaterThan, :formula => "2000", :dxfId => profitable, :priority => 1 })
218
+ # f = File.open('example_differential_styling', 'w')
219
+ # p.serialize(f)
220
+ #
192
221
  def add_style(options={})
193
-
194
- numFmtId = if options[:format_code]
195
- n = @numFmts.map{ |f| f.numFmtId }.max + 1
196
- numFmts << NumFmt.new(:numFmtId => n, :formatCode=> options[:format_code])
197
- n
198
- else
199
- options[:num_fmt] || 0
200
- end
201
-
202
- borderId = options[:border] || 0
203
-
204
- if borderId.is_a?(Hash)
205
- raise ArgumentError, "border hash definitions must include both style and color" unless borderId.keys.include?(:style) && borderId.keys.include?(:color)
206
-
207
- s = borderId.delete :style
208
- c = borderId.delete :color
209
- border = Border.new
210
- [:left, :right, :top, :bottom].each {|pr| border.prs << BorderPr.new(:name => pr, :style=>s, :color => Color.new(:rgb => c))}
211
- borderId = self.borders << border
222
+ # Default to :xf
223
+ options[:type] ||= :xf
224
+ raise ArgumentError, "Type must be one of [:xf, :dxf]" unless [:xf, :dxf].include?(options[:type] )
225
+
226
+ fill = parse_fill_options options
227
+ font = parse_font_options options
228
+ numFmt = parse_num_fmt_options options
229
+ border = parse_border_options options
230
+ alignment = parse_alignment_options options
231
+ protection = parse_protection_options options
232
+
233
+ case options[:type]
234
+ when :dxf
235
+ style = Dxf.new :fill => fill, :font => font, :numFmt => numFmt, :border => border, :alignment => alignment, :protection => protection
236
+ else
237
+ style = Xf.new :fillId=>fill || 0, :fontId=>font || 0, :numFmtId=>numFmt || 0, :borderId=>border || 0, :alignment => alignment, :protection => protection, :applyFill=>!fill.nil?, :applyFont=>!font.nil?, :applyNumberFormat =>!numFmt.nil?, :applyBorder=>!border.nil?, :applyAlignment => !alignment.nil?, :applyProtection => !protection.nil?
212
238
  end
213
239
 
214
- raise ArgumentError, "Invalid borderId" unless borderId < borders.size
240
+ options[:type] == :xf ? cellXfs << style : dxfs << style
241
+ end
215
242
 
216
- fill = if options[:bg_color]
217
- color = Color.new(:rgb=>options[:bg_color])
218
- pattern = PatternFill.new(:patternType =>:solid, :fgColor=>color)
219
- fills << Fill.new(pattern)
220
- else
221
- 0
222
- end
243
+ # parses add_style options for protection styles
244
+ # noop if options hash does not include :hide or :locked key
223
245
 
224
- fontId = if (options.values_at(:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name).length)
225
- font = Font.new()
226
- [:b, :i, :u, :strike, :outline, :shadow, :charset, :family, :sz].each { |k| font.send("#{k}=", options[k]) unless options[k].nil? }
227
- font.color = Color.new(:rgb => options[:fg_color]) unless options[:fg_color].nil?
228
- font.name = options[:font_name] unless options[:font_name].nil?
229
- fonts << font
230
- else
231
- 0
232
- end
246
+ # @option options [Boolean] hide boolean value defining cell protection attribute for hiding.
247
+ # @option options [Boolean] locked boolean value defining cell protection attribute for locking.
248
+ # @return [CellProtection]
249
+ def parse_protection_options(options={})
250
+ return if (options.keys & [:hidden, :locked]).empty?
251
+ CellProtection.new(options)
252
+ end
233
253
 
234
- applyProtection = (options[:hidden] || options[:locked]) ? 1 : 0
254
+ # parses add_style options for alignment
255
+ # noop if options hash does not include :alignment key
256
+ # @option options [Hash] alignment A hash of options to prive the CellAlignment intializer
257
+ # @return [CellAlignment]
258
+ # @see CellAlignment
259
+ def parse_alignment_options(options={})
260
+ return unless options[:alignment]
261
+ CellAlignment.new options[:alignment]
262
+ end
235
263
 
236
- xf = Xf.new(:fillId => fill, :fontId=>fontId, :applyFill=>1, :applyFont=>1, :numFmtId=>numFmtId, :borderId=>borderId, :applyProtection=>applyProtection)
264
+ # parses add_style options for fonts. If the options hash contains :type => :dxf we return a new Font object.
265
+ # if not, we return the index of the newly created font object in the styles.fonts collection.
266
+ # @note noop if none of the options described here are set on the options parameter.
267
+ # @option options [Symbol] type The type of style object we are working with (dxf or xf)
268
+ # @option options [String] fg_color The text color
269
+ # @option options [Integer] sz The text size
270
+ # @option options [Boolean] b Indicates if the text should be bold
271
+ # @option options [Boolean] i Indicates if the text should be italicised
272
+ # @option options [Boolean] u Indicates if the text should be underlined
273
+ # @option options [Boolean] strike Indicates if the text should be rendered with a strikethrough
274
+ # @option options [Boolean] outline Indicates if the text should be rendered with a shadow
275
+ # @option options [Integer] charset The character set to use.
276
+ # @option options [Integer] family The font family to use.
277
+ # @option options [String] font_name The name of the font to use
278
+ # @return [Font|Integer]
279
+ def parse_font_options(options={})
280
+ return if (options.keys & [:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name]).empty?
281
+ font = Font.new(options)
282
+ font.color = Color.new(:rgb => options[:fg_color]) if options[:fg_color]
283
+ font.name = options[:font_name] if options[:font_name]
284
+ options[:type] == :dxf ? font : fonts << font
285
+ end
237
286
 
238
- xf.applyNumberFormat = true if xf.numFmtId > 0
239
- xf.applyBorder = true if borderId > 0
287
+ # parses add_style options for fills. If the options hash contains :type => :dxf we return a Fill object. If not, we return the index of the fill after being added to the fills collection.
288
+ # @note noop if :bg_color is not specified in options
289
+ # @option options [String] bg_color The rgb color to apply to the fill
290
+ # @return [Fill|Integer]
291
+ def parse_fill_options(options={})
292
+ return unless options[:bg_color]
293
+ color = Color.new(:rgb=>options[:bg_color])
294
+ pattern = PatternFill.new(:patternType =>:solid, :fgColor=>color)
295
+ fill = Fill.new(pattern)
296
+ options[:type] == :dxf ? fill : fills << fill
297
+ end
240
298
 
241
- if options[:alignment]
242
- xf.alignment = CellAlignment.new(options[:alignment])
243
- xf.applyAlignment = true
299
+ # parses Style#add_style options for borders.
300
+ # @note noop if :border is not specified in options
301
+ # @option options [Hash|Integer] A border style definition hash or the index of an existing border. Border style definition hashes must include :style and color: key-value entries and may include an :edges entry that references an array of symbols identifying which border edges you wish to apply the style or any other valid Border initializer options. If the :edges entity is not provided the style is applied to all edges of cells that reference this style.
302
+ # @example
303
+ # #apply a thick red border to the top and bottom
304
+ # { :border => { :style => :thick, :color => "FFFF0000", :edges => [:top, :bottom] }
305
+ # @return [Border|Integer]
306
+ def parse_border_options(options={})
307
+ return unless options[:border]
308
+ b_opts = options[:border]
309
+ if b_opts.is_a?(Hash)
310
+ raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % b_opts) unless b_opts.values_at(:style, :color).size == 2
311
+ border = Border.new b_opts
312
+ (b_opts[:edges] || [:left, :right, :top, :bottom]).each do |edge|
313
+ b_options = { :name => edge, :style => b_opts[:style], :color => Color.new(:rgb => b_opts[:color]) }
314
+ border.prs << BorderPr.new(b_options)
315
+ end
316
+ options[:type] == :dxf ? border : borders << border
317
+ elsif b_opts.is_a? Integer
318
+ raise ArgumentError, (ERR_INVALID_BORDER_ID % b_opts) unless b_opts < borders.size
319
+ if options[:type] == :dxf
320
+ borders[b_opts].clone
321
+ else
322
+ border = b_opts
323
+ end
244
324
  end
325
+ end
245
326
 
246
- if applyProtection
247
- xf.protection = CellProtection.new(options)
327
+ # Parses Style#add_style options for number formatting.
328
+ # noop if neither :format_code or :num_format options are set.
329
+ # @option options [Hash] A hash describing the :format_code and/or :num_fmt integer for the style.
330
+ # @return [NumFmt|Integer]
331
+ def parse_num_fmt_options(options={})
332
+ return if (options.keys & [:format_code, :num_fmt]).empty?
333
+
334
+ #When the user provides format_code - we always need to create a new numFmt object
335
+ #When the type is :dxf we always need to create a new numFmt object
336
+ if options[:format_code] || options[:type] == :dxf
337
+ #If this is a standard xf we pull from numFmts the highest current and increment for num_fmt
338
+ options[:num_fmt] ||= (@numFmts.map{ |num_fmt| num_fmt.numFmtId }.max + 1) if options[:type] != :dxf
339
+ numFmt = NumFmt.new(:numFmtId => options[:num_fmt] || 0, :formatCode=> options[:format_code].to_s)
340
+ options[:type] == :dxf ? numFmt : (numFmts << numFmt; numFmt.numFmtId)
341
+ else
342
+ options[:num_fmt]
248
343
  end
249
-
250
- cellXfs << xf
251
344
  end
252
345
 
253
346
  # Serializes the object
@@ -304,7 +397,7 @@ module Axlsx
304
397
  @cellXfs << Xf.new(:borderId=>0, :xfId=>0, :numFmtId=>14, :fontId=>0, :fillId=>0, :applyNumberFormat=>1)
305
398
  @cellXfs.lock
306
399
 
307
- @dxfs = SimpleTypedList.new(Xf, "dxfs"); @dxfs.lock
400
+ @dxfs = SimpleTypedList.new(Dxf, "dxfs"); @dxfs.lock
308
401
  @tableStyles = TableStyles.new(:defaultTableStyle => "TableStyleMedium9", :defaultPivotStyle => "PivotStyleLight16"); @tableStyles.lock
309
402
  end
310
403
  end
@@ -40,10 +40,10 @@ module Axlsx
40
40
  # @param [String] str
41
41
  # @return [String]
42
42
  def to_xml_string(str = '')
43
- attr = self.instance_values.select { |k, v| [:name, :pivot, :table].include? k }
44
- attr[:count] = self.size
43
+ attrs = instance_values.reject { |k, v| ![:name, :pivot, :table].include?(k) }
44
+ attrs[:count] = self.size
45
45
  str << '<tableStyle '
46
- str << attr.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
46
+ str << attrs.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
47
47
  str << '>'
48
48
  each { |table_style_el| table_style_el.to_xml_string(str) }
49
49
  str << '</tableStyle>'
@@ -85,6 +85,7 @@ module Axlsx
85
85
  # @option options [CellProtection] protection
86
86
  def initialize(options={})
87
87
  options.each do |o|
88
+ next if o[1].nil?
88
89
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
89
90
  end
90
91
  end
@@ -139,5 +140,6 @@ module Axlsx
139
140
  str << '</xf>'
140
141
  end
141
142
 
143
+
142
144
  end
143
145
  end
@@ -79,6 +79,18 @@ module Axlsx
79
79
  # image rels namespace
80
80
  HYPERLINK_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
81
81
 
82
+ # comment rels namespace
83
+ COMMENT_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
84
+
85
+ # comment relation for nil target
86
+ COMMENT_R_NULL = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
87
+
88
+ #vml drawing relation namespace
89
+ VML_DRAWING_R = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing'
90
+
91
+ # VML Drawing content type
92
+ VML_DRAWING_CT = "application/vnd.openxmlformats-officedocument.vmlDrawing"
93
+
82
94
  # table content type
83
95
  TABLE_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
84
96
 
@@ -109,6 +121,9 @@ module Axlsx
109
121
  # chart content type
110
122
  CHART_CT = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
111
123
 
124
+ # comments content type
125
+ COMMENT_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
126
+
112
127
  # jpeg content type
113
128
  JPEG_CT = "image/jpeg"
114
129
 
@@ -172,6 +187,9 @@ module Axlsx
172
187
  # drawing rels part
173
188
  DRAWING_RELS_PN = "drawings/_rels/drawing%d.xml.rels"
174
189
 
190
+ # vml drawing part
191
+ VML_DRAWING_PN = "drawings/vmlDrawing%d.vml"
192
+
175
193
  # drawing part
176
194
  TABLE_PN = "tables/table%d.xml"
177
195
 
@@ -181,6 +199,9 @@ module Axlsx
181
199
  # chart part
182
200
  IMAGE_PN = "media/image%d.%s"
183
201
 
202
+ # comment part
203
+ COMMENT_PN = "comments%d.xml"
204
+
184
205
  # location of schema files for validation
185
206
  SCHEMA_BASE = File.dirname(__FILE__)+'/../../schema/'
186
207
 
@@ -228,8 +249,23 @@ module Axlsx
228
249
 
229
250
  # error message for sheets that use a name which is longer than 31 bytes
230
251
  ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be 31 characters (bytes) or less"
252
+
253
+ # error message for sheets that use a name which includes a colon
254
+
255
+ ERR_SHEET_NAME_COLON_FORBIDDEN = "Your worksheet name '%s' contains a colon, which is not allowed by MS Excel and will cause repair warnings. Please change the name of your sheet."
231
256
 
232
257
  # error message for duplicate sheet names
233
258
  ERR_DUPLICATE_SHEET_NAME = "There is already a worksheet in this workbook named '%s'. Please use a unique name"
234
259
 
260
+ # error message when user does not provide color and or style options for border in Style#add_sytle
261
+ ERR_INVALID_BORDER_OPTIONS = "border hash must include both style and color. e.g. :border => { :color => 'FF000000', :style => :thin }. You provided: %s"
262
+
263
+ # error message for invalid border id reference
264
+ ERR_INVALID_BORDER_ID = "The border id you specified (%s) does not exist. Please add a border with Style#add_style before referencing its index."
265
+
266
+ # error message for invalid angles
267
+ ERR_ANGLE = "Angles must be a value between -90 and 90. You provided: %s"
268
+
269
+ # error message for non 'integerish' value
270
+ ERR_INTEGERISH = "You value must be, or be castable via to_i, an Integer. You provided %s"
235
271
  end
@@ -18,7 +18,7 @@ module Axlsx
18
18
 
19
19
  # Creats a new typed list
20
20
  # @param [Array, Class] type An array of Class objects or a single Class object
21
- # @param [String] serialize The tag name to use in serialization
21
+ # @param [String] serialize_as The tag name to use in serialization
22
22
  # @raise [ArgumentError] if all members of type are not Class objects
23
23
  def initialize type, serialize_as=nil
24
24
  if type.is_a? Array
@@ -50,6 +50,18 @@ module Axlsx
50
50
  @locked_at = nil
51
51
  self
52
52
  end
53
+
54
+ # join operator
55
+ # @param [Array] v the array to join
56
+ # @raise [ArgumentError] if any of the values being joined are not
57
+ # one of the allowed types
58
+ # @return [SimpleTypedList]
59
+ def +(v)
60
+ v.each do |item|
61
+ DataTypeValidator.validate "SimpleTypedList.+", @allowed_types, item
62
+ @list << item
63
+ end
64
+ end
53
65
 
54
66
  # Concat operator
55
67
  # @param [Any] v the data to be added
@@ -60,12 +72,7 @@ module Axlsx
60
72
  @list << v
61
73
  @list.size - 1
62
74
  end
63
-
64
- # alternate of << method
65
- # @see <<
66
- def push(v)
67
- self.<< v
68
- end
75
+ alias :push :<<
69
76
 
70
77
  # delete the item from the list
71
78
  # @param [Any] v The item to be deleted.
@@ -149,25 +156,12 @@ module Axlsx
149
156
 
150
157
  def to_xml_string(str = '')
151
158
  classname = @allowed_types[0].name.split('::').last
152
- el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
159
+ el_name = serialize_as.to_s || (classname[0,1].downcase + classname[1..-1])
153
160
  str << '<' << el_name << ' count="' << @list.size.to_s << '">'
154
161
  @list.each { |item| item.to_xml_string(str) }
155
162
  str << '</' << el_name << '>'
156
163
  end
157
164
 
158
- # Serializes the list
159
- # If the serialize_as property is set, it is used as the parent node name.
160
- # If the serialize_as property is nil, the first item in the list of allowed_types will be used, having the first letter of the class changed to lower case.
161
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
162
- # @return [String]
163
- def to_xml(xml)
164
- classname = @allowed_types[0].name.split('::').last
165
- el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
166
- xml.send(el_name, :count=>@list.size) {
167
- @list.each { |item| item.to_xml(xml) }
168
- }
169
- end
170
-
171
165
  end
172
166
 
173
167