axlsx 1.3.4 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
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]