axlsx 1.1.4 → 1.3.1

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 (242) hide show
  1. data/.yardopts +6 -2
  2. data/CHANGELOG.md +72 -0
  3. data/README.md +114 -31
  4. data/Rakefile +11 -3
  5. data/examples/auto_filter.rb +16 -0
  6. data/examples/auto_filter.xlsx +0 -0
  7. data/examples/basic_charts.rb +58 -0
  8. data/examples/chart_colors.rb +17 -2
  9. data/examples/data_validation.rb +50 -0
  10. data/examples/example.rb +171 -60
  11. data/examples/example.xlsx +0 -0
  12. data/examples/example_streamed.xlsx +0 -0
  13. data/examples/extractive.pdf +0 -0
  14. data/examples/extractive.rb +3 -0
  15. data/examples/extractive.xlsx +0 -0
  16. data/examples/hyperlinks.rb +23 -0
  17. data/examples/hyperlinks.xlsx +0 -0
  18. data/examples/no-use_autowidth.xlsx +0 -0
  19. data/examples/page_setup.rb +11 -0
  20. data/examples/page_setup.xlsx +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/axlsx.csv +1 -0
  26. data/examples/skydrive/axlsx.xlsx +0 -0
  27. data/examples/skydrive/real_example.rb +8 -8
  28. data/examples/sprk2012/Screen Shot 2012-09-11 at 10.42.06 PM.png +0 -0
  29. data/examples/sprk2012/Screen Shot 2012-09-11 at 11.07.48 PM.png +0 -0
  30. data/examples/sprk2012/Screen Shot 2012-09-11 at 8.31.50 PM.png +0 -0
  31. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.23.27 PM.png +0 -0
  32. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.32.06 PM.png +0 -0
  33. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.33.35 PM.png +0 -0
  34. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.46.44 PM.png +0 -0
  35. data/examples/sprk2012/Screen Shot 2012-09-12 at 5.07.23 PM.png +0 -0
  36. data/examples/sprk2012/basics.rb +11 -0
  37. data/examples/sprk2012/basics.xlsx +0 -0
  38. data/examples/sprk2012/gravatar.jpeg +0 -0
  39. data/examples/sprk2012/hair_club.jpg +0 -0
  40. data/examples/sprk2012/images.rb +9 -0
  41. data/examples/sprk2012/images.xlsx +0 -0
  42. data/examples/sprk2012/line_chart.rb +56 -0
  43. data/examples/sprk2012/line_chart.xlsx +0 -0
  44. data/examples/sprk2012/sprk2012.key +0 -0
  45. data/examples/sprk2012/styles.rb +20 -0
  46. data/examples/sprk2012/styles.xlsx +0 -0
  47. data/examples/styles.rb +62 -0
  48. data/examples/styles.xlsx +0 -0
  49. data/examples/two_cell_anchor_image.rb +11 -0
  50. data/lib/axlsx/content_type/content_type.rb +2 -0
  51. data/lib/axlsx/content_type/default.rb +30 -15
  52. data/lib/axlsx/content_type/override.rb +29 -14
  53. data/lib/axlsx/doc_props/app.rb +161 -104
  54. data/lib/axlsx/doc_props/core.rb +9 -5
  55. data/lib/axlsx/drawing/ax_data_source.rb +7 -6
  56. data/lib/axlsx/drawing/axis.rb +82 -36
  57. data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
  58. data/lib/axlsx/drawing/bar_series.rb +2 -1
  59. data/lib/axlsx/drawing/cat_axis.rb +43 -39
  60. data/lib/axlsx/drawing/chart.rb +65 -54
  61. data/lib/axlsx/drawing/d_lbls.rb +100 -0
  62. data/lib/axlsx/drawing/drawing.rb +20 -8
  63. data/lib/axlsx/drawing/graphic_frame.rb +2 -1
  64. data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
  65. data/lib/axlsx/drawing/num_data.rb +2 -2
  66. data/lib/axlsx/drawing/num_data_source.rb +4 -1
  67. data/lib/axlsx/drawing/pic.rb +44 -4
  68. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
  69. data/lib/axlsx/drawing/scatter_chart.rb +2 -8
  70. data/lib/axlsx/drawing/title.rb +21 -9
  71. data/lib/axlsx/drawing/two_cell_anchor.rb +46 -9
  72. data/lib/axlsx/drawing/view_3D.rb +42 -32
  73. data/lib/axlsx/drawing/vml_drawing.rb +42 -0
  74. data/lib/axlsx/drawing/vml_shape.rb +125 -0
  75. data/lib/axlsx/package.rb +43 -16
  76. data/lib/axlsx/rels/relationship.rb +3 -3
  77. data/lib/axlsx/rels/relationships.rb +1 -11
  78. data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
  79. data/lib/axlsx/stylesheet/styles.rb +11 -2
  80. data/lib/axlsx/stylesheet/table_style.rb +3 -3
  81. data/lib/axlsx/util/constants.rb +131 -2
  82. data/lib/axlsx/util/simple_typed_list.rb +18 -22
  83. data/lib/axlsx/util/validators.rb +100 -9
  84. data/lib/axlsx/version.rb +2 -7
  85. data/lib/axlsx/workbook/defined_name.rb +174 -0
  86. data/lib/axlsx/workbook/defined_names.rb +21 -0
  87. data/lib/axlsx/workbook/workbook.rb +70 -13
  88. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +77 -0
  89. data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +102 -0
  90. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +253 -0
  91. data/lib/axlsx/workbook/worksheet/cell.rb +41 -8
  92. data/lib/axlsx/workbook/worksheet/col.rb +15 -0
  93. data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
  94. data/lib/axlsx/workbook/worksheet/comment.rb +101 -0
  95. data/lib/axlsx/workbook/worksheet/comments.rb +85 -0
  96. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
  97. data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
  98. data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
  99. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
  100. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +1 -1
  101. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
  102. data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
  103. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +47 -0
  104. data/lib/axlsx/workbook/worksheet/page_setup.rb +241 -0
  105. data/lib/axlsx/workbook/worksheet/pane.rb +144 -0
  106. data/lib/axlsx/workbook/worksheet/print_options.rb +63 -0
  107. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  108. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
  109. data/lib/axlsx/workbook/worksheet/row.rb +36 -20
  110. data/lib/axlsx/workbook/worksheet/selection.rb +111 -0
  111. data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +49 -0
  112. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
  113. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +107 -0
  114. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
  115. data/lib/axlsx/workbook/worksheet/sheet_view.rb +379 -0
  116. data/lib/axlsx/workbook/worksheet/table.rb +10 -3
  117. data/lib/axlsx/workbook/worksheet/table_style_info.rb +68 -0
  118. data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
  119. data/lib/axlsx/workbook/worksheet/worksheet.rb +414 -254
  120. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
  121. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
  122. data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +101 -0
  123. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +38 -0
  124. data/lib/axlsx.rb +38 -16
  125. data/test/content_type/tc_content_type.rb +1 -6
  126. data/test/doc_props/tc_app.rb +31 -1
  127. data/test/doc_props/tc_core.rb +3 -1
  128. data/test/drawing/tc_axis.rb +38 -3
  129. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  130. data/test/drawing/tc_bar_series.rb +1 -2
  131. data/test/drawing/tc_cat_axis.rb +3 -3
  132. data/test/drawing/tc_chart.rb +29 -9
  133. data/test/drawing/tc_d_lbls.rb +47 -0
  134. data/test/drawing/tc_drawing.rb +11 -5
  135. data/test/drawing/tc_hyperlink.rb +4 -5
  136. data/test/drawing/tc_line_series.rb +7 -3
  137. data/test/drawing/tc_num_data.rb +5 -1
  138. data/test/drawing/tc_pic.rb +22 -2
  139. data/test/drawing/tc_pie_3D_chart.rb +4 -8
  140. data/test/drawing/tc_pie_series.rb +7 -2
  141. data/test/drawing/tc_scatter_chart.rb +6 -1
  142. data/test/drawing/tc_scatter_series.rb +1 -1
  143. data/test/drawing/tc_series.rb +1 -1
  144. data/test/drawing/tc_title.rb +16 -0
  145. data/test/drawing/tc_two_cell_anchor.rb +1 -2
  146. data/test/drawing/tc_view_3D.rb +18 -18
  147. data/test/drawing/tc_vml_drawing.rb +25 -0
  148. data/test/drawing/tc_vml_shape.rb +100 -0
  149. data/test/rels/tc_relationship.rb +1 -0
  150. data/test/stylesheet/tc_gradient_fill.rb +8 -0
  151. data/test/stylesheet/tc_pattern_fill.rb +7 -1
  152. data/test/stylesheet/tc_styles.rb +16 -4
  153. data/test/stylesheet/tc_table_style.rb +8 -0
  154. data/test/stylesheet/tc_table_style_element.rb +10 -1
  155. data/test/tc_helper.rb +1 -0
  156. data/test/tc_package.rb +94 -17
  157. data/test/util/tc_simple_typed_list.rb +13 -0
  158. data/test/util/tc_validators.rb +101 -8
  159. data/test/workbook/tc_defined_name.rb +41 -0
  160. data/test/workbook/tc_workbook.rb +5 -3
  161. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +38 -0
  162. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +76 -0
  163. data/test/workbook/worksheet/auto_filter/tc_filters.rb +50 -0
  164. data/test/workbook/worksheet/tc_cell.rb +53 -7
  165. data/test/workbook/worksheet/tc_col.rb +9 -0
  166. data/test/workbook/worksheet/tc_comment.rb +57 -0
  167. data/test/workbook/worksheet/tc_comments.rb +57 -0
  168. data/test/workbook/worksheet/tc_conditional_formatting.rb +44 -0
  169. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  170. data/test/workbook/worksheet/tc_data_validation.rb +265 -0
  171. data/test/workbook/worksheet/tc_page_set_up_pr.rb +15 -0
  172. data/test/workbook/worksheet/tc_page_setup.rb +143 -0
  173. data/test/workbook/worksheet/tc_pane.rb +94 -0
  174. data/test/workbook/worksheet/tc_print_options.rb +72 -0
  175. data/test/workbook/worksheet/tc_protected_range.rb +17 -0
  176. data/test/workbook/worksheet/tc_row.rb +32 -14
  177. data/test/workbook/worksheet/tc_selection.rb +94 -0
  178. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +18 -0
  179. data/test/workbook/worksheet/tc_sheet_pr.rb +27 -0
  180. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
  181. data/test/workbook/worksheet/tc_sheet_view.rb +214 -0
  182. data/test/workbook/worksheet/{table/tc_table.rb → tc_table.rb} +9 -12
  183. data/test/workbook/worksheet/tc_table_style_info.rb +53 -0
  184. data/test/workbook/worksheet/tc_worksheet.rb +155 -51
  185. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +64 -0
  186. metadata +194 -81
  187. data/examples/#extractive.csv# +0 -0
  188. data/examples/#extractive.rb# +0 -45
  189. data/examples/chart_colors.rb~ +0 -0
  190. data/examples/chart_colors.xlsx +0 -0
  191. data/examples/colored_series_data.xlsx +0 -0
  192. data/examples/conditional_formatting/getting_barred.xlsx +0 -0
  193. data/examples/example.csv +0 -1000
  194. data/examples/extractive.csv +0 -1
  195. data/examples/extractive.csv~ +0 -1
  196. data/examples/extractive.rb~ +0 -3
  197. data/examples/stack.rb +0 -21
  198. data/examples/stack.rb~ +0 -27
  199. data/examples/stack.xlsx +0 -0
  200. data/examples/~$chart_colors.xlsx +0 -0
  201. data/examples/~$extractive.xlsx +0 -0
  202. data/lib/axlsx/drawing/ax_data_source.rb~ +0 -55
  203. data/lib/axlsx/drawing/data_source.rb~ +0 -51
  204. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  205. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  206. data/lib/axlsx/drawing/num_data.rb~ +0 -51
  207. data/lib/axlsx/drawing/num_data_source.rb~ +0 -54
  208. data/lib/axlsx/drawing/num_val.rb~ +0 -40
  209. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  210. data/lib/axlsx/drawing/ref.rb~ +0 -41
  211. data/lib/axlsx/drawing/str_data.rb~ +0 -58
  212. data/lib/axlsx/drawing/str_val.rb~ +0 -35
  213. data/lib/axlsx/util/cbf.rb +0 -333
  214. data/lib/axlsx/util/cfb.rb~ +0 -201
  215. data/lib/axlsx/util/font_tables.rb~ +0 -0
  216. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  217. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  218. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  219. data/lib/axlsx/util/parser.rb~ +0 -6
  220. data/lib/axlsx/util/storage.rb~ +0 -0
  221. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  222. data/lib/axlsx/workbook/worksheet/cfvo.rb~ +0 -0
  223. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  224. data/lib/axlsx/workbook/worksheet/color_scale.rb~ +0 -46
  225. data/lib/axlsx/workbook/worksheet/data_bar.rb~ +0 -0
  226. data/lib/axlsx/workbook/worksheet/icon_set.rb~ +0 -95
  227. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  228. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  229. data/lib/schema/dc.xsd~ +0 -118
  230. data/lib/schema/dcterms.xsd~ +0 -331
  231. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  232. data/test/drawing/tc_data_source.rb~ +0 -30
  233. data/test/drawing/tc_num_data.rb~ +0 -35
  234. data/test/drawing/tc_num_val.rb~ +0 -29
  235. data/test/drawing/tc_str_data.rb~ +0 -30
  236. data/test/drawing/tc_str_val.rb~ +0 -26
  237. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  238. data/test/workbook/worksheet/tc_cfvo.rb~ +0 -20
  239. data/test/workbook/worksheet/tc_col.rb~ +0 -10
  240. data/test/workbook/worksheet/tc_color_scale.rb~ +0 -0
  241. data/test/workbook/worksheet/tc_data_bar.rb~ +0 -0
  242. data/test/workbook/worksheet/tc_icon_set.rb~ +0 -0
@@ -0,0 +1,57 @@
1
+ module Axlsx
2
+
3
+ # A wraper class for comments that defines its on worksheet
4
+ # serailization
5
+ class WorksheetComments
6
+
7
+ # Creates a new WorksheetComments object
8
+ # param [Worksheet] worksheet The worksheet comments in thes object belong to
9
+ def initialize(worksheet)
10
+ raise ArugumentError, 'You must provide a worksheet' unless worksheet.is_a?(Worksheet)
11
+ @worksheet = worksheet
12
+ end
13
+
14
+ attr_reader :worksheet
15
+
16
+ # The comments for this worksheet.
17
+ # @return [Comments]
18
+ def comments
19
+ @comments ||= Comments.new(worksheet)
20
+ end
21
+
22
+ # Adds a comment
23
+ # @param [Hash] options
24
+ # @see Comments#add_comment
25
+ def add_comment(options={})
26
+ comments.add_comment(options)
27
+ end
28
+
29
+ # The relationships defined by this objects comments collection
30
+ # @return [Relationships]
31
+ def relationships
32
+ return [] unless has_comments?
33
+ comments.relationships
34
+ end
35
+
36
+
37
+ # Helper method to tell us if there are comments in the comments collection
38
+ # @return [Boolean]
39
+ def has_comments?
40
+ !comments.empty?
41
+ end
42
+
43
+ # The index in the worksheet's relationships for the VML drawing that will render the comments
44
+ # @return [Integer]
45
+ def index
46
+ worksheet.relationships.index { |r| r.Type == VML_DRAWING_R } + 1
47
+ end
48
+
49
+ # Seraalize the object
50
+ # @param [String] str
51
+ # @return [String]
52
+ def to_xml_string(str = '')
53
+ return unless has_comments?
54
+ str << "<legacyDrawing r:id='rId#{index}' />"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,64 @@
1
+ module Axlsx
2
+
3
+ # This is a utility class for serialing the drawing node in a
4
+ # worksheet. Drawing objects have their own serialization that exports
5
+ # a drawing document. This is only for the single node in the
6
+ # worksheet
7
+ class WorksheetDrawing
8
+
9
+ # Creates a new WorksheetDrawing
10
+ # @param [Worksheet] worksheet
11
+ def initialize(worksheet)
12
+ raise ArgumentError, 'you must provide a worksheet' unless worksheet.is_a?(Worksheet)
13
+ @worksheet = worksheet
14
+ @drawing = nil
15
+ end
16
+
17
+ attr_reader :worksheet
18
+
19
+ attr_reader :drawing
20
+
21
+ # adds a chart to the drawing object
22
+ # @param [Class] chart_type The type of chart to add
23
+ # @param [Hash] options Options to pass on to the drawing and chart
24
+ # @see Worksheet#add_chart
25
+ def add_chart(chart_type, options)
26
+ @drawing ||= Drawing.new worksheet
27
+ drawing.add_chart(chart_type, options)
28
+ end
29
+
30
+ # adds an image to the drawing object
31
+ # @param [Hash] options Options to pass on to the drawing and image
32
+ # @see Worksheet#add_image
33
+ def add_image(options)
34
+ @drawing ||= Drawing.new worksheet
35
+ drawing.add_image(options)
36
+ end
37
+
38
+ # helper method to tell us if the drawing has something in it or not
39
+ # @return [Boolean]
40
+ def has_drawing?
41
+ @drawing.is_a? Drawing
42
+ end
43
+
44
+ # The relationship required by this object
45
+ # @return [Relationship]
46
+ def relationship
47
+ return unless has_drawing?
48
+ Relationship.new(DRAWING_R, "../#{drawing.pn}")
49
+ end
50
+
51
+ # returns the index of the worksheet releationship that defines this drawing.
52
+ # @return [Integer]
53
+ def index
54
+ worksheet.relationships.index{ |r| r.Type == DRAWING_R } +1
55
+ end
56
+
57
+ # Serialize the drawing for the worksheet
58
+ # @param [String] str
59
+ def to_xml_string(str = '')
60
+ return unless has_drawing?
61
+ str << "<drawing r:id='rId#{index}'/>"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,101 @@
1
+ module Axlsx
2
+
3
+ # A worksheet hyperlink object. Note that this is not the same as a drawing hyperlink object.
4
+ class WorksheetHyperlink
5
+
6
+ # Creates a new hyperlink object.
7
+ # @note the preferred way to add hyperlinks to your worksheet is the Worksheet#add_hyperlink method
8
+ # @param [Worksheet] worksheet the Worksheet that owns this hyperlink
9
+ # @param [Hash] options options to use when creating this hyperlink
10
+ # @option [String] display Display string, if different from string in string table. This is a property on the hyperlink object, but does not need to appear in the spreadsheet application UI.
11
+ # @option [String] location Location within target. If target is a workbook (or this workbook) this shall refer to a sheet and cell or a defined name. Can also be an HTML anchor if target is HTML file.
12
+ # @option [String] tooltip The tip to display when the user positions the mouse cursor over this hyperlink
13
+ # @option [Symbol] target This is :external by default. If you set it to anything else, the location is interpreted to be the current workbook.
14
+ # @option [String|Cell] ref The location of this hyperlink in the worksheet
15
+ def initialize(worksheet, options={})
16
+ DataTypeValidator.validate "Hyperlink.worksheet", [Worksheet], worksheet
17
+ @worksheet = worksheet
18
+ @target = :external
19
+ options.each do |o|
20
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
21
+ end
22
+ yield self if block_given?
23
+ end
24
+
25
+ # String attributes for this object
26
+ STRING_ATTRIBUTES = %w(display location tooltip)
27
+
28
+ #Cell location of hyperlink on worksheet.
29
+ # @return [String]
30
+ attr_reader :ref
31
+
32
+ # Sets the target for this hyperlink. Anything other than :external instructs the library to treat the location as an in-workbook reference.
33
+ # @param [Symbol] target
34
+ def target=(target)
35
+ @target = target
36
+ end
37
+
38
+ # Sets the cell location of this hyperlink in the worksheet
39
+ # @param [String|Cell] cell_reference The string reference or cell that defines where this hyperlink shows in the worksheet.
40
+ def ref=(cell_reference)
41
+ cell_reference = cell_reference.r if cell_reference.is_a?(Cell)
42
+
43
+ Axlsx::validate_string cell_reference
44
+ @ref = cell_reference
45
+ end
46
+
47
+ # Dynamically create string attribute accessors
48
+ STRING_ATTRIBUTES.each do |attr|
49
+ class_eval %{
50
+ # The #{attr} attribute reader
51
+ # @return [String]
52
+ attr_reader :#{attr}
53
+
54
+ # The #{attr} writer
55
+ # @param [String] value The value to assign to #{attr}
56
+ # @return [String]
57
+ def #{attr}=(value)
58
+ Axlsx::validate_string(value)
59
+ @#{attr}= value
60
+ end
61
+ }
62
+ end
63
+
64
+ # The relationship required by this hyperlink when the taget is :external
65
+ # @return [Relationship]
66
+ def relationship
67
+ return unless @target == :external
68
+ Relationship.new HYPERLINK_R, location, :target_mode => :External
69
+ end
70
+
71
+ # The id of the relationship for this object
72
+ # @return [String]
73
+ def id
74
+ return unless @target == :external
75
+ "rId#{(@worksheet.relationships_index_of(self)+1)}"
76
+ end
77
+
78
+ # Seralize the object
79
+ # @param [String] str
80
+ # @return [String]
81
+ def to_xml_string(str='')
82
+ str << '<hyperlink '
83
+ serialization_values.map { |key, value| str << key.to_s << '="' << value.to_s << '" ' }
84
+ str << '/>'
85
+ end
86
+
87
+ # The values to be used in serialization based on the target.
88
+ # location should only be specified for non-external targets.
89
+ # r:id should only be specified for external targets.
90
+ # @return [Hash]
91
+ def serialization_values
92
+ h = instance_values.reject { |key, value| !%w(display ref tooltip).include?(key) }
93
+ if @target == :external
94
+ h['r:id'] = id
95
+ else
96
+ h['location'] = location
97
+ end
98
+ h
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,38 @@
1
+ module Axlsx
2
+
3
+ #A collection of hyperlink objects for a worksheet
4
+ class WorksheetHyperlinks < SimpleTypedList
5
+
6
+ # Creates a new Hyperlinks collection
7
+ # @param [Worksheet] worksheet the worksheet that owns these hyperlinks
8
+ def initialize(worksheet)
9
+ DataTypeValidator.validate "Hyperlinks.worksheet", [Worksheet], worksheet
10
+ @worksheet = worksheet
11
+ super WorksheetHyperlink
12
+ end
13
+
14
+ # Creates and adds a new hyperlink based on the options provided
15
+ # @see WorksheetHyperlink#initialize
16
+ # @return [WorksheetHyperlink]
17
+ def add(options)
18
+ @list << WorksheetHyperlink.new(@worksheet, options)
19
+ @list.last
20
+ end
21
+
22
+ # The relationships required by this collection's hyperlinks
23
+ # @return Array
24
+ def relationships
25
+ return [] if empty?
26
+ map { |hyperlink| hyperlink.relationship }
27
+ end
28
+
29
+ # seralize the collection of hyperlinks
30
+ # @return [String]
31
+ def to_xml_string(str='')
32
+ return if empty?
33
+ str << '<hyperlinks>'
34
+ @list.each { |hyperlink| hyperlink.to_xml_string(str) }
35
+ str << '</hyperlinks>'
36
+ end
37
+ end
38
+ end
data/lib/axlsx.rb CHANGED
@@ -1,16 +1,10 @@
1
1
  # encoding: UTF-8
2
+ require 'htmlentities'
2
3
  require 'axlsx/version.rb'
3
4
 
4
5
  require 'axlsx/util/simple_typed_list.rb'
5
6
  require 'axlsx/util/constants.rb'
6
7
  require 'axlsx/util/validators.rb'
7
- require 'axlsx/util/storage.rb'
8
-
9
- #not even close to being ready but it does not break anything so it stays for now.
10
- # needs a full re-write to use agile-encryption properly
11
- require 'axlsx/util/cbf.rb'
12
- require 'axlsx/util/ms_off_crypto.rb'
13
-
14
8
 
15
9
  # to be included with parsable intitites.
16
10
  #require 'axlsx/util/parser.rb'
@@ -43,25 +37,44 @@ if !Object.respond_to?(:instance_values)
43
37
  end
44
38
  end
45
39
 
46
- # xlsx generation with charts, images, automated column width, customizable styles and full schema validation. Axlsx excels at helping you generate beautiful Office Open XML Spreadsheet documents without having to understand the entire ECMA specification. Check out the README for some examples of how easy it is. Best of all, you can validate your xlsx file before serialization so you know for sure that anything generated is going to load on your client's machine.
40
+ # xlsx generation with charts, images, automated column width, customizable styles
41
+ # and full schema validation. Axlsx excels at helping you generate beautiful
42
+ # Office Open XML Spreadsheet documents without having to understand the entire
43
+ # ECMA specification. Check out the README for some examples of how easy it is.
44
+ # Best of all, you can validate your xlsx file before serialization so you know
45
+ # for sure that anything generated is going to load on your client's machine.
47
46
  module Axlsx
47
+
48
48
  # determines the cell range for the items provided
49
- def self.cell_range(items)
50
- return "" unless items.first.is_a? Cell
51
- ref = "'#{items.first.row.worksheet.name}'!" +
52
- "#{items.first.r_abs}"
53
- ref += ":#{items.last.r_abs}" if items.size > 1
54
- ref
49
+ def self.cell_range(cells, absolute=true)
50
+ return "" unless cells.first.is_a? Cell
51
+ sort_cells(cells)
52
+ reference = "#{cells.first.reference(absolute)}:#{cells.last.reference(absolute)}"
53
+ absolute ? "'#{cells.first.row.worksheet.name}'!#{reference}" : reference
55
54
  end
56
55
 
56
+ # sorts the array of cells provided to start from the minimum x,y to
57
+ # the maximum x.y#
58
+ # @param [Array] cells
59
+ # @return [Array]
60
+ def self.sort_cells(cells)
61
+ cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
62
+ end
63
+
64
+ #global reference html entity encoding
65
+ # @return [HtmlEntities]
66
+ def self.coder
67
+ @@coder ||= ::HTMLEntities.new
68
+ end
69
+
70
+ # returns the x, y position of a cell
57
71
  def self.name_to_indices(name)
58
72
  raise ArgumentError, 'invalid cell name' unless name.size > 1
73
+ # capitalization?!?
59
74
  v = name[/[A-Z]+/].reverse.chars.reduce({:base=>1, :i=>0}) do |val, c|
60
75
  val[:i] += ((c.bytes.first - 64) * val[:base]); val[:base] *= 26; val
61
76
  end
62
-
63
77
  [v[:i]-1, ((name[/[1-9][0-9]*/]).to_i)-1]
64
-
65
78
  end
66
79
 
67
80
  # converts the column index into alphabetical values.
@@ -84,4 +97,13 @@ module Axlsx
84
97
  Axlsx::col_ref(c_index).to_s << (r_index+1).to_s
85
98
  end
86
99
 
100
+ # performs the increadible feat of changing snake_case to CamelCase
101
+ # @param [String] s The snake case string to camelize
102
+ # @return [String]
103
+ def self.camel(s="", all_caps = true)
104
+ s = s.to_s
105
+ s = s.capitalize if all_caps
106
+ s.gsub(/_(.)/){ $1.upcase }
107
+ end
108
+
87
109
  end
@@ -9,12 +9,7 @@ class TestContentType < Test::Unit::TestCase
9
9
 
10
10
  def test_valid_document
11
11
  schema = Nokogiri::XML::Schema(File.open(Axlsx::CONTENT_TYPES_XSD))
12
- errors = []
13
- schema.validate(@doc).each do |error|
14
- puts error.message
15
- errors << error
16
- end
17
- assert_equal(errors.size, 0, "[Content Types].xml Invalid" + errors.map{ |e| e.message }.to_s)
12
+ assert(schema.validate(@doc).map{ |e| puts e.message; e.message }.empty?)
18
13
  end
19
14
 
20
15
  def test_pre_built_types
@@ -1,9 +1,39 @@
1
1
  require 'tc_helper.rb'
2
2
 
3
3
  class TestApp < Test::Unit::TestCase
4
+ def setup
5
+ options = {
6
+ :'Template' => 'Foo.xlt',
7
+ :'Manager' => 'Penny',
8
+ :'Company' => "Bob's Repair",
9
+ :'Pages' => 1,
10
+ :'Words' => 2,
11
+ :'Characters' => 7,
12
+ :'PresentationFormat' => 'any',
13
+ :'Lines' => 1,
14
+ :'Paragraphs' => 1,
15
+ :'Slides' => 4,
16
+ :'Notes' => 1,
17
+ :'TotalTime' => 2,
18
+ :'HidddenSlides' => 3,
19
+ :'MMClips' => 10,
20
+ :'ScaleCrop' => true,
21
+ :'LinksUpToDate' => true,
22
+ :'CharactersWithSpaces' => 9,
23
+ :'SharedDoc' => false,
24
+ :'HyperlinkBase' => 'foo',
25
+ :'HyperlInksChanged' => false,
26
+ :'Application' => 'axlsx',
27
+ :'AppVersion' => '1.1.5',
28
+ :'DocSecurity' => 0
29
+ }
30
+
31
+ @app = Axlsx::App.new options
32
+
33
+ end
4
34
  def test_valid_document
5
35
  schema = Nokogiri::XML::Schema(File.open(Axlsx::APP_XSD))
6
- doc = Nokogiri::XML(Axlsx::App.new.to_xml_string)
36
+ doc = Nokogiri::XML(@app.to_xml_string)
7
37
  errors = []
8
38
  schema.validate(doc).each do |error|
9
39
  errors << error
@@ -4,6 +4,8 @@ class TestCore < Test::Unit::TestCase
4
4
 
5
5
  def setup
6
6
  @core = Axlsx::Core.new
7
+ # could still see some false positives if the second changes between the next two calls
8
+ @time = Time.now.strftime('%Y-%m-%dT%H:%M:%SZ')
7
9
  @doc = Nokogiri::XML(@core.to_xml_string)
8
10
  end
9
11
 
@@ -18,7 +20,7 @@ class TestCore < Test::Unit::TestCase
18
20
  end
19
21
 
20
22
  def test_populates_created
21
- assert_equal(@doc.xpath('//dcterms:created').text, Time.now.strftime('%Y-%m-%dT%H:%M:%S'), "dcterms:created incorrect")
23
+ assert_equal(@doc.xpath('//dcterms:created').text, @time, "dcterms:created incorrect")
22
24
  end
23
25
 
24
26
  def test_populates_default_name
@@ -2,8 +2,10 @@ require 'tc_helper.rb'
2
2
 
3
3
  class TestAxis < Test::Unit::TestCase
4
4
  def setup
5
- @axis = Axlsx::Axis.new 12345, 54321
5
+
6
+ @axis = Axlsx::Axis.new 12345, 54321, :gridlines => false, :title => 'Foo'
6
7
  end
8
+
7
9
  def teardown
8
10
  end
9
11
 
@@ -13,7 +15,30 @@ class TestAxis < Test::Unit::TestCase
13
15
  assert_equal(@axis.tickLblPos, :nextTo, "tick label position default incorrect")
14
16
  assert_equal(@axis.crosses, :autoZero, "tick label position default incorrect")
15
17
  assert(@axis.scaling.is_a?(Axlsx::Scaling) && @axis.scaling.orientation == :minMax, "scaling default incorrect")
16
- assert_raise(ArgumentError) { Axlsx::Axis.new -1234, 'abcd' }
18
+ assert_raise(ArgumentError) { Axlsx::Axis.new( -1234, 'abcd') }
19
+ assert_equal('Foo', @axis.title.text)
20
+ end
21
+
22
+ def test_color
23
+ @axis.color = "00FF00"
24
+ str = '<?xml version="1.0" encoding="UTF-8"?>'
25
+ str << '<c:chartSpace xmlns:c="' << Axlsx::XML_NS_C << '" xmlns:a="' << Axlsx::XML_NS_A << '">'
26
+ doc = Nokogiri::XML(@axis.to_xml_string(str))
27
+ assert(doc.xpath("//a:srgbClr[@val='00FF00']"))
28
+ end
29
+
30
+ def test_cell_based_axis_title
31
+ p = Axlsx::Package.new
32
+ p.workbook.add_worksheet(:name=>'foosheet') do |sheet|
33
+ sheet.add_row ['battle victories']
34
+ sheet.add_row ['bird', 1, 2, 1]
35
+ sheet.add_row ['cat', 7, 9, 10]
36
+ sheet.add_chart(Axlsx::Line3DChart) do |chart|
37
+ chart.add_series :data => sheet['B2:D2'], :labels => sheet['B1']
38
+ chart.valAxis.title = sheet['A1']
39
+ assert_equal('battle victories', chart.valAxis.title.text)
40
+ end
41
+ end
17
42
  end
18
43
 
19
44
  def test_axis_position
@@ -48,5 +73,15 @@ class TestAxis < Test::Unit::TestCase
48
73
  assert_raise(ArgumentError, "requires valid gridlines") { @axis.gridlines = 'alice' }
49
74
  assert_nothing_raised("accepts valid crosses") { @axis.gridlines = false }
50
75
  end
51
-
76
+
77
+ def test_to_xml_string
78
+ str = '<?xml version="1.0" encoding="UTF-8"?>'
79
+ str << '<c:chartSpace xmlns:c="' << Axlsx::XML_NS_C << '" xmlns:a="' << Axlsx::XML_NS_A << '">'
80
+ doc = Nokogiri::XML(@axis.to_xml_string(str))
81
+ assert(doc.xpath('//a:noFill'))
82
+ assert(doc.xpath("//c:crosses[@val='#{@axis.crosses.to_s}']"))
83
+ assert(doc.xpath("//c:crossAx[@val='#{@axis.crossAx.to_s}']"))
84
+ assert(doc.xpath("//a:bodyPr[@rot='#{@axis.label_rotation.to_s}']"))
85
+ assert(doc.xpath("//a:t[text()='Foo']"))
86
+ end
52
87
  end
@@ -15,15 +15,15 @@ class TestBar3DChart < Test::Unit::TestCase
15
15
  def test_initialization
16
16
  assert_equal(@chart.grouping, :clustered, "grouping defualt incorrect")
17
17
  assert_equal(@chart.series_type, Axlsx::BarSeries, "series type incorrect")
18
- assert_equal(@chart.barDir, :bar, " bar direction incorrect")
19
- assert(@chart.catAxis.is_a?(Axlsx::CatAxis), "category axis not created")
20
- assert(@chart.valAxis.is_a?(Axlsx::ValAxis), "value access not created")
18
+ assert_equal(@chart.bar_dir, :bar, " bar direction incorrect")
19
+ assert(@chart.cat_axis.is_a?(Axlsx::CatAxis), "category axis not created")
20
+ assert(@chart.val_axis.is_a?(Axlsx::ValAxis), "value access not created")
21
21
  end
22
22
 
23
23
  def test_bar_direction
24
- assert_raise(ArgumentError, "require valid bar direction") { @chart.barDir = :left }
25
- assert_nothing_raised("allow valid bar direction") { @chart.barDir = :col }
26
- assert(@chart.barDir == :col)
24
+ assert_raise(ArgumentError, "require valid bar direction") { @chart.bar_dir = :left }
25
+ assert_nothing_raised("allow valid bar direction") { @chart.bar_dir = :col }
26
+ assert(@chart.bar_dir == :col)
27
27
  end
28
28
 
29
29
  def test_grouping
@@ -34,15 +34,15 @@ class TestBar3DChart < Test::Unit::TestCase
34
34
 
35
35
 
36
36
  def test_gapWidth
37
- assert_raise(ArgumentError, "require valid gap width") { @chart.gapWidth = 200 }
38
- assert_nothing_raised("allow valid gapWidth") { @chart.gapWidth = "200%" }
39
- assert(@chart.gapWidth == "200%")
37
+ assert_raise(ArgumentError, "require valid gap width") { @chart.gap_width = 200 }
38
+ assert_nothing_raised("allow valid gapWidth") { @chart.gap_width = "200%" }
39
+ assert(@chart.gap_width == "200%")
40
40
  end
41
41
 
42
42
  def test_gapDepth
43
- assert_raise(ArgumentError, "require valid gapDepth") { @chart.gapDepth = 200 }
44
- assert_nothing_raised("allow valid gapDepth") { @chart.gapDepth = "200%" }
45
- assert(@chart.gapDepth == "200%")
43
+ assert_raise(ArgumentError, "require valid gap_depth") { @chart.gap_depth = 200 }
44
+ assert_nothing_raised("allow valid gap_depth") { @chart.gap_depth = "200%" }
45
+ assert(@chart.gap_depth == "200%")
46
46
  end
47
47
 
48
48
  def test_shape
@@ -5,7 +5,7 @@ class TestBarSeries < Test::Unit::TestCase
5
5
  def setup
6
6
  p = Axlsx::Package.new
7
7
  @ws = p.workbook.add_worksheet :name=>"hmmm"
8
- @chart = @ws.drawing.add_chart Axlsx::Bar3DChart, :title => "fishery"
8
+ @chart = @ws.add_chart Axlsx::Bar3DChart, :title => "fishery"
9
9
  @series = @chart.add_series :data=>[0,1,2], :labels=>["zero", "one", "two"], :title=>"bob", :colors => ['FF0000', '00FF00', '0000FF'], :shape => :cone
10
10
  end
11
11
 
@@ -33,6 +33,5 @@ class TestBarSeries < Test::Unit::TestCase
33
33
  assert_equal(doc.xpath("//c:dPt/c:idx[@val='#{index}']").size,1)
34
34
  assert_equal(doc.xpath("//c:dPt/c:spPr/a:solidFill/a:srgbClr[@val='#{@series.colors[index]}']").size,1)
35
35
  end
36
- assert_equal(doc.xpath("//c:shape[@val='#{@series.shape.to_s}']").size, 1)
37
36
  end
38
37
  end
@@ -10,7 +10,7 @@ class TestCatAxis < Test::Unit::TestCase
10
10
  def test_initialization
11
11
  assert_equal(@axis.auto, 1, "axis auto default incorrect")
12
12
  assert_equal(@axis.lblAlgn, :ctr, "label align default incorrect")
13
- assert_equal(@axis.lblOffset, "100%", "label offset default incorrect")
13
+ assert_equal(@axis.lblOffset, "100", "label offset default incorrect")
14
14
  end
15
15
 
16
16
  def test_auto
@@ -24,8 +24,8 @@ class TestCatAxis < Test::Unit::TestCase
24
24
  end
25
25
 
26
26
  def test_lblOffset
27
- assert_raise(ArgumentError, "requires valid label offset") { @axis.lblOffset = 100 }
28
- assert_nothing_raised("accepts valid label offset") { @axis.lblOffset = "20%" }
27
+ assert_raise(ArgumentError, "requires valid label offset") { @axis.lblOffset = 'foo' }
28
+ assert_nothing_raised("accepts valid label offset") { @axis.lblOffset = "20" }
29
29
  end
30
30
 
31
31
  end
@@ -22,11 +22,16 @@ class TestChart < Test::Unit::TestCase
22
22
  @chart.title.text = 'wowzer'
23
23
  assert_equal(@chart.title.text, "wowzer", "the title text via a string")
24
24
  assert_equal(@chart.title.cell, nil, "the title cell is nil as we set the title with text.")
25
- @chart.title.cell = @row.cells.first
25
+ @chart.title = @row.cells.first
26
26
  assert_equal(@chart.title.text, "one", "the title text was set via cell reference")
27
27
  assert_equal(@chart.title.cell, @row.cells.first)
28
28
  end
29
29
 
30
+ def test_to_from_marker_access
31
+ assert(@chart.to.is_a?(Axlsx::Marker))
32
+ assert(@chart.from.is_a?(Axlsx::Marker))
33
+ end
34
+
30
35
  def test_style
31
36
  assert_raise(ArgumentError) { @chart.style = 49 }
32
37
  assert_nothing_raised { @chart.style = 2 }
@@ -34,16 +39,29 @@ class TestChart < Test::Unit::TestCase
34
39
  end
35
40
 
36
41
  def test_start_at
37
- @chart.start_at 15,25
42
+ @chart.start_at 15, 25
38
43
  assert_equal(@chart.graphic_frame.anchor.from.col, 15)
39
44
  assert_equal(@chart.graphic_frame.anchor.from.row, 25)
40
-
45
+ @chart.start_at @row.cells.first
46
+ assert_equal(@chart.graphic_frame.anchor.from.col, 0)
47
+ assert_equal(@chart.graphic_frame.anchor.from.row, 0)
48
+ @chart.start_at [5,6]
49
+ assert_equal(@chart.graphic_frame.anchor.from.col, 5)
50
+ assert_equal(@chart.graphic_frame.anchor.from.row, 6)
51
+
41
52
  end
42
53
 
43
54
  def test_end_at
44
55
  @chart.end_at 25, 90
45
56
  assert_equal(@chart.graphic_frame.anchor.to.col, 25)
46
57
  assert_equal(@chart.graphic_frame.anchor.to.row, 90)
58
+ @chart.end_at @row.cells.last
59
+ assert_equal(@chart.graphic_frame.anchor.to.col, 2)
60
+ assert_equal(@chart.graphic_frame.anchor.to.row, 0)
61
+ @chart.end_at [10,11]
62
+ assert_equal(@chart.graphic_frame.anchor.to.col, 10)
63
+ assert_equal(@chart.graphic_frame.anchor.to.row, 11)
64
+
47
65
  end
48
66
 
49
67
  def test_add_series
@@ -55,15 +73,17 @@ class TestChart < Test::Unit::TestCase
55
73
  def test_pn
56
74
  assert_equal(@chart.pn, "charts/chart1.xml")
57
75
  end
58
-
76
+
77
+ def test_d_lbls
78
+ assert_equal(nil, @chart.instance_values[:d_lbls])
79
+ @chart.d_lbls.d_lbl_pos = :t
80
+ assert(@chart.d_lbls.is_a?(Axlsx::DLbls), 'DLbls instantiated on access')
81
+ end
82
+
59
83
  def test_to_xml_string
60
84
  schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD))
61
85
  doc = Nokogiri::XML(@chart.to_xml_string)
62
- errors = []
63
- schema.validate(doc).each do |error|
64
- errors.push error
65
- puts error.message
66
- end
86
+ errors = schema.validate(doc).map { |error| puts error.message; error }
67
87
  assert(errors.empty?, "error free validation")
68
88
  end
69
89