axlsx 1.3.4 → 1.3.5

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 (46) hide show
  1. data/README.md +27 -5
  2. data/examples/example.rb +31 -9
  3. data/examples/ios_preview.rb +14 -0
  4. data/examples/pivot_table.rb +39 -0
  5. data/examples/styles.rb +4 -0
  6. data/lib/axlsx.rb +28 -0
  7. data/lib/axlsx/drawing/bar_3D_chart.rb +15 -10
  8. data/lib/axlsx/drawing/chart.rb +13 -1
  9. data/lib/axlsx/drawing/drawing.rb +12 -11
  10. data/lib/axlsx/drawing/graphic_frame.rb +6 -1
  11. data/lib/axlsx/drawing/hyperlink.rb +5 -0
  12. data/lib/axlsx/drawing/line_3D_chart.rb +3 -2
  13. data/lib/axlsx/drawing/pic.rb +6 -0
  14. data/lib/axlsx/drawing/pie_3D_chart.rb +2 -1
  15. data/lib/axlsx/drawing/scatter_chart.rb +2 -1
  16. data/lib/axlsx/package.rb +13 -0
  17. data/lib/axlsx/rels/relationship.rb +1 -0
  18. data/lib/axlsx/stylesheet/styles.rb +22 -18
  19. data/lib/axlsx/util/accessors.rb +15 -0
  20. data/lib/axlsx/util/constants.rb +25 -5
  21. data/lib/axlsx/util/validators.rb +10 -8
  22. data/lib/axlsx/version.rb +1 -1
  23. data/lib/axlsx/workbook/shared_strings_table.rb +1 -1
  24. data/lib/axlsx/workbook/workbook.rb +27 -3
  25. data/lib/axlsx/workbook/worksheet/cell.rb +26 -64
  26. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +144 -0
  27. data/lib/axlsx/workbook/worksheet/col.rb +9 -2
  28. data/lib/axlsx/workbook/worksheet/pivot_table.rb +259 -0
  29. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +65 -0
  30. data/lib/axlsx/workbook/worksheet/pivot_tables.rb +24 -0
  31. data/lib/axlsx/workbook/worksheet/row.rb +10 -1
  32. data/lib/axlsx/workbook/worksheet/sheet_format_pr.rb +60 -0
  33. data/lib/axlsx/workbook/worksheet/worksheet.rb +55 -6
  34. data/test/benchmark.rb +1 -0
  35. data/test/drawing/tc_chart.rb +7 -0
  36. data/test/drawing/tc_graphic_frame.rb +5 -0
  37. data/test/example.xlsx +0 -0
  38. data/test/profile.rb +1 -0
  39. data/test/tc_axlsx.rb +15 -0
  40. data/test/tc_package.rb +13 -5
  41. data/test/workbook/worksheet/tc_cell.rb +5 -1
  42. data/test/workbook/worksheet/tc_pivot_table.rb +102 -0
  43. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +46 -0
  44. data/test/workbook/worksheet/tc_sheet_format_pr.rb +88 -0
  45. data/test/workbook/worksheet/tc_worksheet.rb +45 -1
  46. metadata +23 -9
data/README.md CHANGED
@@ -21,7 +21,7 @@ appreciation for the gem, please don't hesitate to make a donation.
21
21
 
22
22
  **License**: MIT License
23
23
 
24
- **Latest Version**: 1.3.4
24
+ **Latest Version**: 1.3.5
25
25
 
26
26
  **Ruby Version**: 1.8.7, 1.9.2, 1.9.3
27
27
 
@@ -29,7 +29,7 @@ appreciation for the gem, please don't hesitate to make a donation.
29
29
 
30
30
  **Rubinius Version**: rubinius 2.0.0dev * lower versions may run, this gem always tests against head.
31
31
 
32
- **Release Date**: November ??th 2012
32
+ **Release Date**: February 4th 2013
33
33
 
34
34
  If you are working in rails, or with active record see:
35
35
  * http://github.com/randym/acts_as_xlsx
@@ -152,6 +152,19 @@ This gem has 100% test coverage using test/unit. To execute tests for this gem,
152
152
 
153
153
  #Change log
154
154
  ---------
155
+ - **February.4.13**:1.3.5
156
+ - converted vary_colors for chart data to instance variable with appropriate defulats for the various charts.
157
+ - Added trust_input method on Axlsx to instruct the serializer to skip HTML escaping. This will give you a tremendous performance boost,
158
+ Please be sure that you will never have <, >, etc in your content or the XML will be invalid.
159
+ - Rewrote cell serialization to improve performance
160
+ - Added iso_8601 type to support text based date and time management.
161
+ - Bug fix for relationahip management in drawings when you add images
162
+ and charts to the same worksheet drawing.
163
+ - Added outline_level_rows and outline_level_columns to worksheet to simplify setting up outlining in the worksheet.
164
+ - Added support for pivot tables
165
+ - Added support for descrete border edge styles
166
+ - Improved validation of sheet names
167
+ - Added support for formula value caching so that iOS and OSX preview can show the proper values. See Cell.add_row and the formula_values option.
155
168
  - **November.25.12**:1.3.4
156
169
  - Support for headers and footers for worksheets
157
170
  - bug fix: Properly escape hyperlink urls
@@ -240,11 +253,20 @@ done without the help of the people below.
240
253
 
241
254
  [ebenoist](https://github.com/ebenoist) - For taking control of control characters and keeping what is between the lines, between the lines.
242
255
 
243
- [adammathys](https://github.com/adammathys) - Fgr getting our head in the
256
+ [adammathys](https://github.com/adammathys) - For getting our head in the
244
257
  air and our feet on the ground.
245
258
 
259
+ [raiis](https://github.com/raiis) - For letting us specify diffent border styles on any edge.
260
+
261
+ [alexrothenberg](https://github.com/alexrothenberg) - For an outstanding implementation of PivotTables, one of the last BIG chunks missing from the spec.
262
+
263
+ [ball-hayden](https://github.com/ball-hayden) - For making sure we only get the right characters in our sheet names.
264
+
265
+ [nibus](https://github.com/nibus) - For patching sheet name unequeness.
266
+
246
267
  #Copyright and License
247
268
  ----------
248
269
 
249
- Axlsx &copy; 2011-2012 by [Randy Morgan](mailto:digial.ipseity@gmail.com). Axlsx is
250
- licensed under the MIT license. Please see the LICENSE document for more information.
270
+ Axlsx &copy; 2011-2012 by [Randy Morgan](mailto:digial.ipseity@gmail.com).
271
+
272
+ Axlsx is licensed under the MIT license. Please see the LICENSE document for more information.
@@ -14,6 +14,7 @@ examples << :surrounding_border
14
14
  examples << :deep_custom_borders
15
15
  examples << :row_column_style
16
16
  examples << :fixed_column_width
17
+ examples << :outline_level
17
18
  examples << :merge_cells
18
19
  examples << :images
19
20
  examples << :format_dates
@@ -21,6 +22,7 @@ examples << :mbcs
21
22
  examples << :formula
22
23
  examples << :auto_filter
23
24
  examples << :data_types
25
+ examples << :override_data_types
24
26
  examples << :hyperlinks
25
27
  examples << :number_currency_format
26
28
  examples << :venezuela_currency
@@ -43,7 +45,7 @@ examples << :conditional_formatting
43
45
  examples << :streaming
44
46
  examples << :shared_strings
45
47
  examples << :no_autowidth
46
-
48
+ examples << :cached_formula
47
49
  p = Axlsx::Package.new
48
50
  wb = p.workbook
49
51
  #```
@@ -237,6 +239,17 @@ if examples.include? :fixed_column_width
237
239
  sheet.column_widths nil, 3, 5, nil
238
240
  end
239
241
  end
242
+
243
+ #```ruby
244
+ if examples.include? :outline_level
245
+ wb.add_worksheet(name: 'outline_level') do |sheet|
246
+ sheet.add_row [1, 2, 3, Time.now, 5, 149455.15]
247
+ sheet.add_row [1, 2, 5, 6, 5,14100.19]
248
+ sheet.add_row [9500002267, 1212, 1212, 5,14100.19]
249
+ sheet.outline_level_rows 0, 2
250
+ sheet.outline_level_columns 0, 2
251
+ end
252
+ end
240
253
  ##```
241
254
 
242
255
  ##Merging Cells.
@@ -344,6 +357,12 @@ if examples.include? :data_types
344
357
  end
345
358
  end
346
359
 
360
+ #```ruby
361
+ if examples.include? :override_data_types
362
+ wb.add_worksheet(:name => "Override Data Type") do |sheet|
363
+ sheet.add_row ['dont eat my zeros!', '0088'] , :types => [nil, :string]
364
+ end
365
+ end
347
366
  # Hyperlinks in worksheet
348
367
  if examples.include? :hyperlinks
349
368
  wb.add_worksheet(:name => 'hyperlinks') do |sheet|
@@ -490,7 +509,7 @@ end
490
509
  if examples.include? :fit_to_page
491
510
  wb.add_worksheet(:name => "fit to page") do |sheet|
492
511
  sheet.add_row ['this all goes on one page']
493
- sheet.fit_to_page = true
512
+ sheet.page_setup.fit_to :width => 1, :height => 1
494
513
  end
495
514
  end
496
515
  ##```
@@ -502,7 +521,7 @@ end
502
521
  if examples.include? :hide_gridlines
503
522
  wb.add_worksheet(:name => "No Gridlines") do |sheet|
504
523
  sheet.add_row ["This", "Sheet", "Hides", "Gridlines"]
505
- sheet.show_gridlines = false
524
+ sheet.sheet_view.show_grid_lines = false
506
525
  end
507
526
  end
508
527
  ##```
@@ -704,11 +723,6 @@ if examples.include? :shared_strings
704
723
  end
705
724
  #```
706
725
 
707
- #p.validate do |er|
708
- #puts er.inspect
709
- #end
710
- ##Disabling Autowidth
711
-
712
726
  #```ruby
713
727
  if examples.include? :no_autowidth
714
728
  p = Axlsx::Package.new
@@ -717,11 +731,19 @@ if examples.include? :no_autowidth
717
731
  wb.add_worksheet(:name => "Manual Widths") do | sheet |
718
732
  sheet.add_row ['oh look! no autowidth']
719
733
  end
720
- p.validate.each { |e| puts e.message }
721
734
  p.serialize("no-use_autowidth.xlsx")
722
735
  end
723
736
  #```
724
737
 
725
738
 
726
739
 
740
+ if examples.include? :cached_formula
741
+ p = Axlsx::Package.new
742
+ p.use_shared_strings = true
743
+ wb = p.workbook
744
+ wb.add_worksheet(:name => "cached formula") do | sheet |
745
+ sheet.add_row [1, 2, '=A1+B1'], :formula_values => [nil, nil, 3]
746
+ end
747
+ p.serialize 'cached_formula.xlsx'
748
+ end
727
749
 
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby -w -s
2
+ # -*- coding: utf-8 -*-
3
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
4
+
5
+ #```ruby
6
+ require 'axlsx'
7
+
8
+ p = Axlsx::Package.new
9
+ p.use_shared_strings = true
10
+ s = p.workbook.add_worksheet(:name => "Formula test")
11
+ s.add_row [1, 2, 3]
12
+ s.add_row %w(a b c)
13
+ s.add_row ["=SUM(A1:C1)"], :formula_values => [6]
14
+ p.serialize "ios_preview.xlsx"
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby -w -s
2
+ # -*- coding: utf-8 -*-
3
+
4
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
5
+ require 'axlsx'
6
+
7
+ p = Axlsx::Package.new
8
+ wb = p.workbook
9
+
10
+ # Create some data in a sheet
11
+ def month
12
+ %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec).sample
13
+ end
14
+ def year
15
+ %w(2010 2011 2012).sample
16
+ end
17
+ def type
18
+ %w(Meat Dairy Beverages Produce).sample
19
+ end
20
+ def sales
21
+ rand(5000)
22
+ end
23
+ def region
24
+ %w(East West North South).sample
25
+ end
26
+
27
+ wb.add_worksheet(:name => "Data Sheet") do |sheet|
28
+ sheet.add_row ['Month', 'Year', 'Type', 'Sales', 'Region']
29
+ 30.times { sheet.add_row [month, year, type, sales, region] }
30
+ sheet.add_pivot_table 'G4:L17', "A1:E31" do |pivot_table|
31
+ pivot_table.rows = ['Month', 'Year']
32
+ pivot_table.columns = ['Type']
33
+ pivot_table.data = ['Sales']
34
+ pivot_table.pages = ['Region']
35
+ end
36
+ end
37
+
38
+ # Write the excel file
39
+ p.serialize("pivot_table.xlsx")
@@ -48,6 +48,9 @@ wb.styles do |style|
48
48
  # A style that a applies a font size and a custom formatting code
49
49
  custom_format = wb.styles.add_style :sz => 20, :format_code => 'yyyy-mm-dd'
50
50
 
51
+ # A style that overrides top and left border style
52
+ override_border = wb.styles.add_style :border => { :style => :thin, :color =>"FAAC58", :edges => [:right, :top, :left] }, :border_top => { :style => :thick, :color => "01DF74" }, :border_left => { :color => "0101DF" }
53
+
51
54
 
52
55
  wb.add_worksheet do |sheet|
53
56
 
@@ -55,6 +58,7 @@ wb.styles do |style|
55
58
  sheet.add_row [123, "123", Time.now], style: [nil, large_font, predefined_format]
56
59
  sheet.add_row [123, "123", Date.new(2012, 9, 14)], style: [large_font, nil, custom_format]
57
60
  sheet.add_row [123, "123", Date.new(2000, 9, 12)] # This uses the axlsx default format_code (14)
61
+ sheet.add_row [123, "123", Time.now], style: [large_font, override_border, predefined_format]
58
62
  end
59
63
 
60
64
  end
@@ -104,6 +104,20 @@ module Axlsx
104
104
  Axlsx::col_ref(c_index).to_s << (r_index+1).to_s
105
105
  end
106
106
 
107
+ # Creates an array of individual cell references based on an excel reference range.
108
+ # @param [String] range A cell range, for example A1:D5
109
+ # @return [Array]
110
+ def self.range_to_a(range)
111
+ range.match(/^(\w+?\d+)\:(\w+?\d+)$/)
112
+ start_col, start_row = name_to_indices($1)
113
+ end_col, end_row = name_to_indices($2)
114
+ (start_row..end_row).to_a.map do |row_num|
115
+ (start_col..end_col).to_a.map do |col_num|
116
+ "#{col_ref(col_num)}#{row_num+1}"
117
+ end
118
+ end
119
+ end
120
+
107
121
  # performs the increadible feat of changing snake_case to CamelCase
108
122
  # @param [String] s The snake case string to camelize
109
123
  # @return [String]
@@ -113,4 +127,18 @@ module Axlsx
113
127
  s.gsub(/_(.)/){ $1.upcase }
114
128
  end
115
129
 
130
+
131
+ # Instructs the serializer to not try to escape cell value input.
132
+ # This will give you a huge speed bonus, but if you content has <, > or other xml character data
133
+ # the workbook will be invalid and excel will complain.
134
+ def self.trust_input
135
+ @trust_input ||= false
136
+ end
137
+
138
+ # @param[Boolean] trust_me A boolean value indicating if the cell value content is to be trusted
139
+ # @return [Boolean]
140
+ # @see Axlsx::trust_input
141
+ def self.trust_input=(trust_me)
142
+ @trust_input = trust_me
143
+ end
116
144
  end
@@ -21,7 +21,9 @@ module Axlsx
21
21
  # The direction of the bars in the chart
22
22
  # must be one of [:bar, :col]
23
23
  # @return [Symbol]
24
- attr_reader :bar_dir
24
+ def bar_dir
25
+ @bar_dir ||= :bar
26
+ end
25
27
  alias :barDir :bar_dir
26
28
 
27
29
  # space between bar or column clusters, as a percentage of the bar or column width.
@@ -31,18 +33,24 @@ module Axlsx
31
33
 
32
34
  # space between bar or column clusters, as a percentage of the bar or column width.
33
35
  # @return [String]
34
- attr_reader :gap_width
36
+ def gap_width
37
+ @gap_width ||= 150
38
+ end
35
39
  alias :gapWidth :gap_width
36
-
40
+
37
41
  #grouping for a column, line, or area chart.
38
42
  # must be one of [:percentStacked, :clustered, :standard, :stacked]
39
43
  # @return [Symbol]
40
- attr_reader :grouping
44
+ def grouping
45
+ @grouping ||= :clustered
46
+ end
41
47
 
42
48
  # The shabe of the bars or columns
43
49
  # must be one of [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax]
44
50
  # @return [Symbol]
45
- attr_reader :shape
51
+ def shape
52
+ @shape ||= :box
53
+ end
46
54
 
47
55
  # validation regex for gap amount percent
48
56
  GAP_AMOUNT_PERCENT = /0*(([0-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/
@@ -65,10 +73,7 @@ module Axlsx
65
73
  # @see Chart
66
74
  # @see View3D
67
75
  def initialize(frame, options={})
68
- @bar_dir = :bar
69
- @grouping = :clustered
70
- @shape = :box
71
- @gap_width = 150
76
+ @vary_colors = true
72
77
  @gap_width, @gap_depth, @shape = nil, nil, nil
73
78
  @cat_ax_id = rand(8 ** 8)
74
79
  @val_ax_id = rand(8 ** 8)
@@ -124,7 +129,7 @@ module Axlsx
124
129
  str_inner << '<c:bar3DChart>'
125
130
  str_inner << '<c:barDir val="' << bar_dir.to_s << '"/>'
126
131
  str_inner << '<c:grouping val="' << grouping.to_s << '"/>'
127
- str_inner << '<c:varyColors val="1"/>'
132
+ str_inner << '<c:varyColors val="' << vary_colors.to_s << '"/>'
128
133
  @series.each { |ser| ser.to_xml_string(str_inner) }
129
134
  @d_lbls.to_xml_string(str) if @d_lbls
130
135
  str_inner << '<c:gapWidth val="' << @gap_width.to_s << '"/>' unless @gap_width.nil?
@@ -49,6 +49,13 @@ module Axlsx
49
49
  @d_lbls ||= DLbls.new(self.class)
50
50
  end
51
51
 
52
+ # Indicates that colors should be varied by datum
53
+ # @return [Boolean]
54
+ attr_reader :vary_colors
55
+
56
+ # Configures the vary_colors options for this chart
57
+ # @param [Boolean] v The value to set
58
+ def vary_colors=(v) Axlsx::validate_boolean(v); @vary_colors = v; end
52
59
 
53
60
  # The title object for the chart.
54
61
  # @return [Title]
@@ -63,6 +70,12 @@ module Axlsx
63
70
  # @return [Boolean]
64
71
  attr_reader :show_legend
65
72
 
73
+ # returns a relationship object for the chart
74
+ # @return [Axlsx::Relationship]
75
+ def relationship
76
+ Relationship.new(CHART_R, "../#{pn}")
77
+ end
78
+
66
79
  # The index of this chart in the workbooks charts collection
67
80
  # @return [Integer]
68
81
  def index
@@ -127,7 +140,6 @@ module Axlsx
127
140
  str << '<c:style val="' << style.to_s << '"/>'
128
141
  str << '<c:chart>'
129
142
  @title.to_xml_string str
130
- # do these need the c: namespace as well???
131
143
  str << '<c:autoTitleDeleted val="' << (@title == nil).to_s << '"/>'
132
144
  @view_3D.to_xml_string(str) if @view_3D
133
145
  str << '<c:floor><c:thickness val="0"/></c:floor>'
@@ -132,6 +132,7 @@ module Axlsx
132
132
  end
133
133
 
134
134
  # The relational part name for this drawing
135
+ # #NOTE This should be rewritten to return an Axlsx::Relationship object.
135
136
  # @return [String]
136
137
  def rels_pn
137
138
  "#{DRAWING_RELS_PN % (index+1)}"
@@ -139,23 +140,23 @@ module Axlsx
139
140
 
140
141
  # The index of a chart, image or hyperlink object this drawing contains
141
142
  def index_of(object)
142
- objects = charts + images + hyperlinks
143
- objects.index(object)
143
+ child_objects.index(object)
144
+ end
145
+
146
+
147
+ # An ordered list of objects this drawing holds
148
+ # It is important that the objects are returned in the same order each time for
149
+ # releationship indexing in the package
150
+ # @return [Array]
151
+ def child_objects
152
+ charts + images + hyperlinks
144
153
  end
145
154
 
146
155
  # The drawing's relationships.
147
156
  # @return [Relationships]
148
157
  def relationships
149
158
  r = Relationships.new
150
- charts.each do |chart|
151
- r << Relationship.new(CHART_R, "../#{chart.pn}")
152
- end
153
- images.each do |image|
154
- r << Relationship.new(IMAGE_R, "../#{image.pn}")
155
- end
156
- hyperlinks.each do |hyperlink|
157
- r << Relationship.new(HYPERLINK_R, hyperlink.href, :target_mode => :External)
158
- end
159
+ child_objects.each { |child| r << child.relationship }
159
160
  r
160
161
  end
161
162
 
@@ -24,7 +24,12 @@ module Axlsx
24
24
 
25
25
  # The relationship id for this graphic
26
26
  # @return [String]
27
+ #
28
+ # NOTE: Discontinued. This should not be part of GraphicFrame.
29
+ # The drawing object maintains relationships and needs to be queried to determine the relationship id of any given graphic data child object.
30
+ #
27
31
  def rId
32
+ warn('axlsx::DEPRECIATED: GraphicFrame#rId has been depreciated. relationship id is determed by the drawing object')
28
33
  "rId#{@anchor.index+1}"
29
34
  end
30
35
 
@@ -44,7 +49,7 @@ module Axlsx
44
49
  str << '</xdr:xfrm>'
45
50
  str << '<a:graphic>'
46
51
  str << '<a:graphicData uri="' << XML_NS_C << '">'
47
- str << '<c:chart xmlns:c="' << XML_NS_C << '" xmlns:r="' << XML_NS_R << '" r:id="' << rId.to_s << '"/>'
52
+ str << '<c:chart xmlns:c="' << XML_NS_C << '" xmlns:r="' << XML_NS_R << '" r:id="rId' << (@anchor.drawing.index_of(@chart)+1).to_s << '"/>'
48
53
  str << '</a:graphicData>'
49
54
  str << '</a:graphic>'
50
55
  str << '</xdr:graphicFrame>'
@@ -83,6 +83,11 @@ module Axlsx
83
83
  # @return [String]
84
84
  attr_accessor :tooltip
85
85
 
86
+ # Returns a relationship object for this hyperlink
87
+ # @return [Axlsx::Relationship]
88
+ def relationship
89
+ Relationship.new(HYPERLINK_R, href, :target_mode => :External)
90
+ end
86
91
  # Serializes the object
87
92
  # @param [String] str
88
93
  # @return [String]