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,253 @@
1
+ module Axlsx
2
+
3
+ # When multiple values are chosen to filter by, or when a group of date values are chosen to filter by,
4
+ # this object groups those criteria together.
5
+ class Filters
6
+
7
+ # Allowed calendar types
8
+ CALENDAR_TYPES = %w(gregorian gregorianUs gregorianMeFrench gregorianArabic hijri hebrew taiwan japan thai korea saka gregorianXlitEnglish gregorianXlitFrench none)
9
+
10
+ # Creates a new Filters object
11
+ # @param [Hash] options Options used to set this objects attributes and
12
+ # create filter and/or date group items
13
+ # @option [Boolean] blank @see blank
14
+ # @option [String] calendar_type @see calendar_type
15
+ # @option [Array] filter_items An array of values that will be used to create filter objects.
16
+ # @option [Array] date_group_items An array of hases defining date group item filters to apply.
17
+ # @note The recommended way to interact with filter objects is via AutoFilter#add_column
18
+ # @example
19
+ # ws.auto_filter.add_column(0, :filters, :blank => true, :calendar_type => 'japan', :filter_items => [100, 'a'])
20
+ def initialize(options={})
21
+ options.each do |key, value|
22
+ self.send("#{key}=", value) if self.respond_to? "#{key}="
23
+ end
24
+ end
25
+
26
+ # Flag indicating whether to filter by blank.
27
+ # @return [Boolean]
28
+ attr_reader :blank
29
+
30
+ # Calendar type for date grouped items.
31
+ # Used to interpret the values in dateGroupItem.
32
+ # This is the calendar type used to evaluate all dates in the filter column,
33
+ # even when those dates are not using the same calendar system / date formatting.
34
+ attr_reader :calendar_type
35
+
36
+ # Tells us if the row of the cell provided should be filterd as it
37
+ # does not meet any of the specified filter_items or
38
+ # date_group_items restrictions.
39
+ # @param [Cell] cell The cell to test against items
40
+ # TODO implement this for date filters as well!
41
+ def apply(cell)
42
+ return false unless cell
43
+ filter_items.each do |filter|
44
+ return false if cell.value == filter.val
45
+ end
46
+ true
47
+ end
48
+
49
+ # The filter values in this filters object
50
+ def filter_items
51
+ @filter_items ||= []
52
+ end
53
+
54
+ # the date group values in this filters object
55
+ def date_group_items
56
+ @date_group_items ||= []
57
+ end
58
+
59
+ # @see calendar_type
60
+ # @param [String] calendar The calendar type to use. This must be one of the types defined in CALENDAR_TYPES
61
+ # @return [String]
62
+ def calendar_type=(calendar)
63
+ RestrictionValidator.validate 'Filters.calendar_type', CALENDAR_TYPES, calendar
64
+ @calendar_type = calendar
65
+ end
66
+
67
+ # Set the value for blank
68
+ # @see blank
69
+ def blank=(use_blank)
70
+ Axlsx.validate_boolean use_blank
71
+ @blank = use_blank
72
+ end
73
+
74
+ # Serialize the object to xml
75
+ def to_xml_string(str = '')
76
+ str << "<filters #{serialized_attributes}>"
77
+ filter_items.each { |filter| filter.to_xml_string(str) }
78
+ date_group_items.each { |date_group_item| date_group_item.to_xml_string(str) }
79
+ str << '</filters>'
80
+ end
81
+
82
+ # not entirely happy with this.
83
+ # filter_items should be a simple typed list that overrides << etc
84
+ # to create Filter objects from the inserted values. However this
85
+ # is most likely so rarely used...(really? do you know that?)
86
+ def filter_items=(values)
87
+ values.each do |value|
88
+ filter_items << Filter.new(value)
89
+ end
90
+ end
91
+
92
+ # Date group items are date group filter items where you specify the
93
+ # date_group and a value for that option as part of the auto_filter
94
+ # @note This can be specified, but will not be applied to the date
95
+ # values in your workbook at this time.
96
+ def date_group_items=(options)
97
+ options.each do |date_group|
98
+ raise ArgumentError, "date_group_items should be an array of hashes specifying the options for each date_group_item" unless date_group.is_a?(Hash)
99
+ date_group_items << DateGroupItem.new(date_group)
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def serialized_attributes(str='')
106
+ instance_values.each do |key, value|
107
+ if %(blank claendar_type).include? key.to_s
108
+ str << "#{Axlsx.camel(key, false)}='#{value}' "
109
+ end
110
+ end
111
+ str
112
+ end
113
+
114
+ # This class expresses a filter criteria value.
115
+ class Filter
116
+
117
+ # Creates a new filter value object
118
+ # @param [Any] value The value of the filter. This is not restricted, but
119
+ # will be serialized via to_s so if you are passing an object
120
+ # be careful.
121
+ def initialize(value)
122
+ @val = value
123
+ end
124
+
125
+
126
+ #Filter value used in the criteria.
127
+ attr_accessor :val
128
+
129
+ # Serializes the filter value object
130
+ # @param [String] str The string to concact the serialization information to.
131
+ def to_xml_string(str = '')
132
+ str << "<filter val='#{@val.to_s}' />"
133
+ end
134
+ end
135
+
136
+
137
+ # This collection is used to express a group of dates or times which are
138
+ # used in an AutoFilter criteria. Values are always written in the calendar
139
+ # type of the first date encountered in the filter range, so that all
140
+ # subsequent dates, even when formatted or represented by other calendar
141
+ # types, can be correctly compared for the purposes of filtering.
142
+ class DateGroupItem
143
+
144
+ # Allowed date time groupings
145
+ DATE_TIME_GROUPING = %w(year month day hour minute second)
146
+
147
+ # Creates a new DateGroupItem
148
+ # @param [Hash] options A hash of options to use when
149
+ # instanciating the object
150
+ # @option [String] date_time_grouping the part of the date this
151
+ # filter should apply for grouping
152
+ # @option [Integer|String] year @see year
153
+ # @option [Integer] month @see month
154
+ # @option [Integer] day @see day
155
+ # @option [Integer] hour @see hour
156
+ # @option [Integer] minute @see minute
157
+ # @option [Integer] second @see second
158
+ def initialize(options={})
159
+ raise ArgumentError, "You must specify a year for date time grouping" unless options[:year]
160
+ raise ArgumentError, "You must specify a date_time_grouping when creating a DateGroupItem for auto filter" unless options[:date_time_grouping]
161
+ options.each do |key, value|
162
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
163
+ end
164
+ end
165
+
166
+ # Grouping level
167
+ # This must be one of year, month, day, hour, minute or second.
168
+ # @return [String]
169
+ attr_reader :date_time_grouping
170
+
171
+ # Year (4 digits)
172
+ # @return [Integer|String]
173
+ attr_reader :year
174
+
175
+ # Month (1..12)
176
+ # @return [Integer]
177
+ attr_reader :month
178
+
179
+ # Day (1-31)
180
+ # @return [Integer]
181
+ attr_reader :day
182
+
183
+ # Hour (0..23)
184
+ # @return [Integer]
185
+ attr_reader :hour
186
+
187
+ # Minute (0..59(
188
+ # @return [Integer]
189
+ attr_reader :minute
190
+
191
+ # Second (0..59)
192
+ # @return [Integer]
193
+ attr_reader :second
194
+
195
+ # The year value for the date group item
196
+ # This must be a four digit value
197
+ def year=(value)
198
+ RegexValidator.validate "DateGroupItem.year", /\d{4}/, value
199
+ @year = value
200
+ end
201
+
202
+ # The month value for the date group item
203
+ # This must be between 1 and 12
204
+ def month=(value)
205
+ RangeValidator.validate "DateGroupItem.month", 0, 12, value
206
+ @month = value
207
+ end
208
+
209
+ # The day value for the date group item
210
+ # This must be between 1 and 31
211
+ # @note no attempt is made to ensure the date value is valid for any given month
212
+ def day=(value)
213
+ RangeValidator.validate "DateGroupItem.day", 0, 31, value
214
+ @day = value
215
+ end
216
+
217
+ # The hour value for the date group item
218
+ # # this must be between 0 and 23
219
+ def hour=(value)
220
+ RangeValidator.validate "DateGroupItem.hour", 0, 23, value
221
+ @hour = value
222
+ end
223
+
224
+ # The minute value for the date group item
225
+ # This must be between 0 and 59
226
+ def minute=(value)
227
+ RangeValidator.validate "DateGroupItem.minute", 0, 59, value
228
+ @minute = value
229
+ end
230
+
231
+ # The second value for the date group item
232
+ # This must be between 0 and 59
233
+ def second=(value)
234
+ RangeValidator.validate "DateGroupItem.second", 0, 59, value
235
+ @second = value
236
+ end
237
+
238
+ # The date time grouping for this filter.
239
+ def date_time_grouping=(grouping)
240
+ RestrictionValidator.validate 'DateGroupItem.date_time_grouping', DATE_TIME_GROUPING, grouping.to_s
241
+ @date_time_grouping = grouping.to_s
242
+ end
243
+
244
+ # Serialize the object to xml
245
+ # @param [String] str The string object this serialization will be concatenated to.
246
+ def to_xml_string(str = '')
247
+ str << '<dateGroupItem '
248
+ instance_values.each { |key, value| str << "#{key}='#{value.to_s}' " }
249
+ str << '/>'
250
+ end
251
+ end
252
+ end
253
+ end
@@ -142,7 +142,7 @@ module Axlsx
142
142
  # The inline color property for the cell
143
143
  # @return [Color]
144
144
  attr_reader :color
145
- # @param [String] The 8 character representation for an rgb color #FFFFFFFF"
145
+ # @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
146
146
  def color=(v)
147
147
  @color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
148
148
  @is_text_run = true
@@ -195,7 +195,7 @@ module Axlsx
195
195
  # @option options [Symbol] scheme must be one of :none, major, :minor
196
196
  def initialize(row, value="", options={})
197
197
  self.row=row
198
- @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
198
+ @value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
199
199
  @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
200
200
  @styles = row.worksheet.workbook.styles
201
201
  @row.cells << self
@@ -261,9 +261,8 @@ module Axlsx
261
261
  # @return [String]
262
262
  def run_xml_string(str = '')
263
263
  if is_text_run?
264
- data = self.instance_values.reject{|key, value| value == nil }
264
+ data = instance_values.reject{|key, value| value == nil || key == 'value' || key == 'type' }
265
265
  keys = data.keys & INLINE_STYLES
266
- keys.delete ['value', 'type']
267
266
  str << "<r><rPr>"
268
267
  keys.each do |key|
269
268
  case key
@@ -272,7 +271,7 @@ module Axlsx
272
271
  when 'color'
273
272
  str << data[key].to_xml_string
274
273
  else
275
- "<" << key.to_s << " val='" << data[key].to_s << "'/>"
274
+ str << "<" << key.to_s << " val='" << data[key].to_s << "'/>"
276
275
  end
277
276
  end
278
277
  str << "</rPr>" << "<t>" << value.to_s << "</t></r>"
@@ -288,13 +287,15 @@ module Axlsx
288
287
  # @param [String] str The string index the cell content will be appended to. Defaults to empty string.
289
288
  # @return [String] xml text for the cell
290
289
  def to_xml_string(r_index, c_index, str = '')
291
- return str if @value.nil?
292
290
  str << '<c r="' << Axlsx::cell_r(c_index, r_index) << '" s="' << @style.to_s << '" '
291
+ return str << '/>' if @value.nil?
292
+
293
293
  case @type
294
+
294
295
  when :string
295
296
  #parse formula
296
297
  if @value.start_with?('=')
297
- str << 't="str"><f>' << @value.to_s.gsub('=', '') << '</f>'
298
+ str << 't="str"><f>' << @value.to_s.sub('=', '') << '</f>'
298
299
  else
299
300
  #parse shared
300
301
  if @ssti
@@ -316,8 +317,40 @@ module Axlsx
316
317
  str << '</c>'
317
318
  end
318
319
 
320
+ def is_formula?
321
+ @type == :string && @value.to_s.start_with?('=')
322
+ end
323
+
324
+ # This is still not perfect...
325
+ # - scaling is not linear as font sizes increst
326
+ # - different fonts have different mdw and char widths
327
+ def autowidth
328
+ return if is_formula? || value == nil
329
+ mdw = 1.78 #This is the widest width of 0..9 in arial@10px)
330
+ font_scale = (font_size/10.0).to_f
331
+ ((value.to_s.count(Worksheet.thin_chars) * mdw + 5) / mdw * 256) / 256.0 * font_scale
332
+ end
333
+
334
+ # returns the absolute or relative string style reference for
335
+ # this cell.
336
+ # @param [Boolean] absolute -when false a relative reference will be
337
+ # returned.
338
+ # @return [String]
339
+ def reference(absolute=true)
340
+ absolute ? r_abs : r
341
+ end
342
+
319
343
  private
320
344
 
345
+ # we scale the font size if bold style is applied to either the style font or
346
+ # the cell itself. Yes, it is a bit of a hack, but it is much better than using
347
+ # imagemagick and loading metrics for every character.
348
+ def font_size
349
+ font = @styles.fonts[@styles.cellXfs[style].fontId] || @styles.fonts[0]
350
+ size_from_styles = (font.b || b) ? font.sz * 1.5 : font.sz
351
+ sz || size_from_styles
352
+ end
353
+
321
354
  # Utility method for setting inline style attributes
322
355
  def set_run_style( validator, attr, value)
323
356
  return unless INLINE_STYLES.include?(attr.to_s)
@@ -352,7 +385,7 @@ module Axlsx
352
385
  :boolean
353
386
  elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
354
387
  :integer
355
- elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
388
+ elsif v.to_s.match(/\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/) #float
356
389
  :float
357
390
  else
358
391
  :string
@@ -102,6 +102,21 @@ module Axlsx
102
102
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
103
103
  end
104
104
  end
105
+
106
+ # updates the width for this col based on the cells autowidth and
107
+ # an optionally specified fixed width
108
+ # @param [Cell] cell The cell to use in updating this col's width
109
+ # @param [Integer] fixed_width If this is specified the width is set
110
+ # to this value and the cell's attributes are ignored.
111
+ # @param [Boolean] use_autowidth If this is false, the cell's
112
+ # autowidth value will be ignored.
113
+ def update_width(cell, fixed_width=nil, use_autowidth=true)
114
+ if fixed_width.is_a? Numeric
115
+ self.width = fixed_width
116
+ elsif use_autowidth
117
+ self.width = [width || 0, cell.autowidth || 0].max
118
+ end
119
+ end
105
120
 
106
121
  # Serialize this columns data to an xml string
107
122
  # @param [String] str
@@ -0,0 +1,20 @@
1
+ module Axlsx
2
+
3
+ # The cols class manages the col object used to manage column widths.
4
+ # This is where the magic happens with autowidth
5
+ class Cols < SimpleTypedList
6
+
7
+ def initialize(worksheet)
8
+ raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
9
+ super Col
10
+ @worksheet = worksheet
11
+ end
12
+
13
+ def to_xml_string(str = '')
14
+ return if empty?
15
+ str << '<cols>'
16
+ each { |item| item.to_xml_string(str) }
17
+ str << '</cols>'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,101 @@
1
+ module Axlsx
2
+
3
+ # A comment is the text data for a comment
4
+ class Comment
5
+
6
+ # The text to render
7
+ # @return [String]
8
+ attr_reader :text
9
+
10
+ # The author of this comment
11
+ # @see Comments
12
+ # @return [String]
13
+ attr_reader :author
14
+
15
+ # The owning Comments object
16
+ # @return [Comments]
17
+ attr_reader :comments
18
+
19
+
20
+ # The string based cell position reference (e.g. 'A1') that determines the positioning of this comment
21
+ # @return [String]
22
+ attr_reader :ref
23
+
24
+ # TODO
25
+ # r (Rich Text Run)
26
+ # rPh (Phonetic Text Run)
27
+ # phoneticPr (Phonetic Properties)
28
+
29
+ def initialize(comments, options={})
30
+ raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments)
31
+ @comments = comments
32
+ options.each do |o|
33
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
34
+ end
35
+ yield self if block_given?
36
+ end
37
+
38
+ # The vml shape that will render this comment
39
+ # @return [VmlShape]
40
+ def vml_shape
41
+ @vml_shape ||= initialize_vml_shape
42
+ end
43
+
44
+ #
45
+ # The index of this author in a unique sorted list of all authors in
46
+ # the comment.
47
+ # @return [Integer]
48
+ def author_index
49
+ @comments.authors.index(author)
50
+ end
51
+
52
+ # @see ref
53
+ def ref=(v)
54
+ Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v
55
+ @ref = v if v.is_a?(String)
56
+ @ref = v.r if v.is_a?(Cell)
57
+ end
58
+
59
+ # @see text
60
+ def text=(v)
61
+ Axlsx::validate_string(v)
62
+ @text = v
63
+ end
64
+
65
+ # @see author
66
+ def author=(v)
67
+ @author = v
68
+ end
69
+
70
+ # serialize the object
71
+ # @param [String] str
72
+ # @return [String]
73
+ def to_xml_string(str = "")
74
+ author = @comments.authors[author_index]
75
+ str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">'
76
+ str << '<text><r>'
77
+ str << '<rPr> <b/><color indexed="81"/></rPr>'
78
+ str << '<t>' << author.to_s << ':
79
+ </t></r>'
80
+ str << '<r>'
81
+ str << '<rPr><color indexed="81"/></rPr>'
82
+ str << '<t>' << text << '</t></r></text>'
83
+ str << '</comment>'
84
+ end
85
+
86
+ private
87
+
88
+ # initialize the vml shape based on this comment's ref/position in the worksheet.
89
+ # by default, all columns are 5 columns wide and 5 rows high
90
+ def initialize_vml_shape
91
+ pos = Axlsx::name_to_indices(ref)
92
+ @vml_shape = VmlShape.new(:row => pos[1], :column => pos[0]) do |vml|
93
+ vml.left_column = vml.column
94
+ vml.right_column = vml.column + 2
95
+ vml.top_row = vml.row
96
+ vml.bottom_row = vml.row + 4
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,85 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Axlsx
3
+
4
+ # Comments is a collection of Comment objects for a worksheet
5
+ class Comments < SimpleTypedList
6
+
7
+ # the vml_drawing that holds the shapes for comments
8
+ # @return [VmlDrawing]
9
+ attr_reader :vml_drawing
10
+
11
+ # The worksheet that these comments belong to
12
+ # @return [Worksheet]
13
+ attr_reader :worksheet
14
+
15
+ # The index of this collection in the workbook. Effectively the index of the worksheet.
16
+ # @return [Integer]
17
+ def index
18
+ @worksheet.index
19
+ end
20
+
21
+ # The part name for this object
22
+ # @return [String]
23
+ def pn
24
+ "#{COMMENT_PN % (index+1)}"
25
+ end
26
+
27
+ # Creates a new Comments object
28
+ # @param [Worksheet] worksheet The sheet that these comments belong to.
29
+ def initialize(worksheet)
30
+ raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
31
+ super(Comment)
32
+ @worksheet = worksheet
33
+ @vml_drawing = VmlDrawing.new(self)
34
+ end
35
+
36
+ # Adds a new comment to the worksheet that owns these comments.
37
+ # @note the author, text and ref options are required
38
+ # @option options [String] author The name of the author for this comment
39
+ # @option options [String] text The text for this comment
40
+ # @option options [Stirng|Cell] ref The cell that this comment is attached to.
41
+ def add_comment(options={})
42
+ raise ArgumentError, "Comment require an author" unless options[:author]
43
+ raise ArgumentError, "Comment requires text" unless options[:text]
44
+ raise ArgumentError, "Comment requires ref" unless options[:ref]
45
+ @list << Comment.new(self, options)
46
+ yield @list.last if block_given?
47
+ @list.last
48
+ end
49
+
50
+ # A sorted list of the unique authors in the contained comments
51
+ # @return [Array]
52
+ def authors
53
+ @list.map { |comment| comment.author.to_s }.uniq.sort
54
+ end
55
+
56
+ # The relationships required by this object
57
+ # @return [Array]
58
+ def relationships
59
+ [Relationship.new(VML_DRAWING_R, "../#{vml_drawing.pn}"),
60
+ Relationship.new(COMMENT_R, "../#{pn}"),
61
+ Relationship.new(COMMENT_R_NULL, "NULL")]
62
+ end
63
+
64
+ # serialize the object
65
+ # @param [String] str
66
+ # @return [String]
67
+ def to_xml_string(str="")
68
+ str << '<?xml version="1.0" encoding="UTF-8"?>'
69
+ str << '<comments xmlns="' << XML_NS << '">'
70
+ str << '<authors>'
71
+ authors.each do |author|
72
+ str << '<author>' << author.to_s << '</author>'
73
+ end
74
+ str << '</authors>'
75
+ str << '<commentList>'
76
+ @list.each do |comment|
77
+ comment.to_xml_string str
78
+ end
79
+ str << '</commentList></comments>'
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,25 @@
1
+ module Axlsx
2
+
3
+ # A simple, self serializing class for storing conditional formattings
4
+ class ConditionalFormattings < SimpleTypedList
5
+
6
+ # creates a new Tables object
7
+ def initialize(worksheet)
8
+ raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
9
+ super ConditionalFormatting
10
+ @worksheet = worksheet
11
+ end
12
+
13
+ # The worksheet that owns this collection of tables
14
+ # @return [Worksheet]
15
+ attr_reader :worksheet
16
+
17
+ # serialize the conditional formattings
18
+ def to_xml_string(str = "")
19
+ return if empty?
20
+ each { |item| item.to_xml_string(str) }
21
+ end
22
+ end
23
+
24
+ end
25
+
@@ -65,7 +65,7 @@ module Axlsx
65
65
  def showValue=(v); Axlsx.validate_boolean(v); @showValue = v end
66
66
 
67
67
  # Sets the color for the data bars.
68
- # @param [Color|String] The color object, or rgb string value to apply
68
+ # @param [Color|String] v The color object, or rgb string value to apply
69
69
  def color=(v)
70
70
  @color = v if v.is_a? Color
71
71
  self.color.rgb = v if v.is_a? String