write_xlsx 0.72.2 → 0.72.3.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/{README.rdoc → Changes} +3 -94
  3. data/README.md +96 -0
  4. data/lib/write_xlsx/chart.rb +115 -259
  5. data/lib/write_xlsx/chart/axis.rb +4 -4
  6. data/lib/write_xlsx/chart/bar.rb +1 -1
  7. data/lib/write_xlsx/chart/column.rb +1 -1
  8. data/lib/write_xlsx/chart/pie.rb +3 -3
  9. data/lib/write_xlsx/chart/radar.rb +1 -1
  10. data/lib/write_xlsx/chart/scatter.rb +1 -1
  11. data/lib/write_xlsx/chart/series.rb +0 -37
  12. data/lib/write_xlsx/chartsheet.rb +25 -37
  13. data/lib/write_xlsx/col_name.rb +40 -0
  14. data/lib/write_xlsx/drawing.rb +95 -85
  15. data/lib/write_xlsx/format.rb +32 -32
  16. data/lib/write_xlsx/package/app.rb +18 -23
  17. data/lib/write_xlsx/package/button.rb +15 -12
  18. data/lib/write_xlsx/package/comments.rb +33 -30
  19. data/lib/write_xlsx/package/conditional_format.rb +18 -14
  20. data/lib/write_xlsx/package/content_types.rb +22 -17
  21. data/lib/write_xlsx/package/core.rb +19 -24
  22. data/lib/write_xlsx/package/relationships.rb +10 -13
  23. data/lib/write_xlsx/package/shared_strings.rb +8 -16
  24. data/lib/write_xlsx/package/styles.rb +59 -64
  25. data/lib/write_xlsx/package/table.rb +27 -37
  26. data/lib/write_xlsx/package/vml.rb +23 -21
  27. data/lib/write_xlsx/package/xml_writer_simple.rb +3 -6
  28. data/lib/write_xlsx/sheets.rb +4 -4
  29. data/lib/write_xlsx/sparkline.rb +22 -22
  30. data/lib/write_xlsx/utility.rb +61 -33
  31. data/lib/write_xlsx/version.rb +1 -1
  32. data/lib/write_xlsx/workbook.rb +46 -50
  33. data/lib/write_xlsx/worksheet.rb +149 -133
  34. data/lib/write_xlsx/worksheet/cell_data.rb +8 -6
  35. data/lib/write_xlsx/worksheet/data_validation.rb +14 -14
  36. data/lib/write_xlsx/worksheet/hyperlink.rb +97 -65
  37. data/lib/write_xlsx/worksheet/page_setup.rb +23 -22
  38. data/test/chart/test_write_a_latin.rb +3 -3
  39. data/test/regression/test_chart_font01.rb +1 -1
  40. data/test/regression/test_chart_font02.rb +1 -1
  41. data/test/regression/test_chart_font03.rb +1 -1
  42. data/test/regression/test_chart_font04.rb +1 -1
  43. data/test/regression/test_chart_font05.rb +1 -1
  44. data/test/regression/test_chart_font06.rb +1 -1
  45. data/test/test_xml_writer_simple.rb +3 -3
  46. data/test/worksheet/test_write_hyperlink.rb +4 -4
  47. data/test/worksheet/test_write_worksheet_attributes.rb +3 -3
  48. data/write_xlsx.gemspec +2 -1
  49. metadata +9 -8
  50. data/test/package/table/test_write_xml_declaration.rb +0 -20
@@ -14,17 +14,19 @@ class CellData # :nodoc:
14
14
  #
15
15
  def cell_attributes #:nodoc:
16
16
  xf_index = xf ? xf.get_xf_index : 0
17
- attributes = ['r', xl_rowcol_to_cell(row, col)]
17
+ attributes = [
18
+ ['r', xl_rowcol_to_cell(row, col)]
19
+ ]
18
20
 
19
21
  # Add the cell format index.
20
22
  if xf_index != 0
21
- attributes << 's' << xf_index
23
+ attributes << ['s', xf_index]
22
24
  elsif @worksheet.set_rows[row] && @worksheet.set_rows[row][1]
23
25
  row_xf = @worksheet.set_rows[row][1]
24
- attributes << 's' << row_xf.get_xf_index
26
+ attributes << ['s', row_xf.get_xf_index]
25
27
  elsif @worksheet.col_formats[col]
26
28
  col_xf = @worksheet.col_formats[col]
27
- attributes << 's' << col_xf.get_xf_index
29
+ attributes << ['s', col_xf.get_xf_index]
28
30
  end
29
31
  attributes
30
32
  end
@@ -63,7 +65,7 @@ def data
63
65
 
64
66
  def write_cell
65
67
  attributes = cell_attributes
66
- attributes << 't' << 's'
68
+ attributes << ['t', 's']
67
69
  @worksheet.writer.tag_elements('c', attributes) do
68
70
  @worksheet.write_cell_value(token)
69
71
  end
@@ -87,7 +89,7 @@ def data
87
89
  def write_cell
88
90
  attributes = cell_attributes
89
91
  if @result && !(@result.to_s =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
90
- attributes << 't' << 'str'
92
+ attributes << ['t', 'str']
91
93
  end
92
94
  @worksheet.writer.tag_elements('c', attributes) do
93
95
  @worksheet.write_cell_formula(token)
@@ -128,23 +128,23 @@ def attributes
128
128
  end
129
129
  end
130
130
 
131
- attributes << 'type' << @validate
132
- attributes << 'operator' << @criteria if @criteria != 'between'
131
+ attributes << ['type', @validate]
132
+ attributes << ['operator', @criteria] if @criteria != 'between'
133
133
 
134
134
  if @error_type
135
- attributes << 'errorStyle' << 'warning' if @error_type == 1
136
- attributes << 'errorStyle' << 'information' if @error_type == 2
135
+ attributes << ['errorStyle', 'warning'] if @error_type == 1
136
+ attributes << ['errorStyle', 'information'] if @error_type == 2
137
137
  end
138
- attributes << 'allowBlank' << 1 if @ignore_blank != 0
139
- attributes << 'showDropDown' << 1 if @dropdown == 0
140
- attributes << 'showInputMessage' << 1 if @show_input != 0
141
- attributes << 'showErrorMessage' << 1 if @show_error != 0
142
-
143
- attributes << 'errorTitle' << @error_title if @error_title
144
- attributes << 'error' << @error_message if @error_message
145
- attributes << 'promptTitle' << @input_title if @input_title
146
- attributes << 'prompt' << @input_message if @input_message
147
- attributes << 'sqref' << sqref
138
+ attributes << ['allowBlank', 1] if @ignore_blank != 0
139
+ attributes << ['showDropDown', 1] if @dropdown == 0
140
+ attributes << ['showInputMessage', 1] if @show_input != 0
141
+ attributes << ['showErrorMessage', 1] if @show_error != 0
142
+
143
+ attributes << ['errorTitle', @error_title] if @error_title
144
+ attributes << ['error', @error_message] if @error_message
145
+ attributes << ['promptTitle', @input_title] if @input_title
146
+ attributes << ['prompt', @input_message] if @input_message
147
+ attributes << ['sqref', sqref]
148
148
  end
149
149
 
150
150
  def has_key?(key)
@@ -8,104 +8,136 @@ class Hyperlink # :nodoc:
8
8
  attr_reader :url, :link_type, :str, :url_str
9
9
  attr_accessor :tip, :display
10
10
 
11
- def initialize(url, str = nil)
12
- link_type = 1
13
-
14
- # Remove the URI scheme from internal links.
11
+ def self.factory(url, str = nil)
15
12
  if url =~ /^internal:/
16
- url = url.sub(/^internal:/, '')
17
- link_type = 2
18
- # Remove the URI scheme from external links.
13
+ InternalHyperlink.new(url, str)
19
14
  elsif url =~ /^external:/
20
- url = url.sub(/^external:/, '')
21
- link_type = 3
15
+ ExternalHyperlink.new(url, str)
16
+ else
17
+ new(url, str)
22
18
  end
19
+ end
20
+
21
+ def initialize(url, str = nil)
22
+ @link_type = 1
23
23
 
24
24
  # The displayed string defaults to the url string.
25
25
  str ||= url.dup
26
26
 
27
- # For external links change the directory separator from Unix to Dos.
28
- if link_type == 3
29
- url = url.gsub(%r|/|, '\\')
30
- str.gsub!(%r|/|, '\\')
31
- end
32
-
33
27
  # Strip the mailto header.
34
28
  str.sub!(/^mailto:/, '')
35
29
 
36
- # Copy string for use in hyperlink elements.
37
- url_str = str.dup
38
-
39
- # External links to URLs and to other Excel workbooks have slightly
40
- # different characteristics that we have to account for.
41
- if link_type == 1
42
- # Escape URL unless it looks already escaped.
43
- unless url =~ /%[0-9a-fA-F]{2}/
44
- # Escape the URL escape symbol.
45
- url = url.gsub(/%/, "%25")
46
-
47
- # Escape whitespae in URL.
48
- url = url.gsub(/[\s\x00]/, '%20')
49
-
50
- # Escape other special characters in URL.
51
- re = /(["<>\[\]`^{}])/
52
- while re =~ url
53
- match = $~[1]
54
- url = url.sub(re, sprintf("%%%x", match.ord))
55
- end
56
- end
30
+ # Escape URL unless it looks already escaped.
31
+ unless url =~ /%[0-9a-fA-F]{2}/
32
+ # Escape the URL escape symbol.
33
+ url = url.gsub(/%/, "%25")
57
34
 
58
- # Ordinary URL style external links don't have a "location" string.
59
- url_str = nil
60
- elsif link_type == 3
61
- # External Workbook links need to be modified into the right format.
62
- # The URL will look something like 'c:\temp\file.xlsx#Sheet!A1'.
63
- # We need the part to the left of the # as the URL and the part to
64
- # the right as the "location" string (if it exists).
65
- url, url_str = url.split(/#/)
66
-
67
- # Add the file:/// URI to the url if non-local.
68
- if url =~ %r![:]! || # Windows style "C:/" link.
69
- url =~ %r!^\\\\! # Network share.
70
- url = "file:///#{url}"
71
- end
72
-
73
- # Convert a ./dir/file.xlsx link to dir/file.xlsx.
74
- url = url.sub(%r!^.\\!, '')
35
+ # Escape whitespae in URL.
36
+ url = url.gsub(/[\s\x00]/, '%20')
75
37
 
76
- # Treat as a default external link now that the data has been modified.
77
- link_type = 1
38
+ # Escape other special characters in URL.
39
+ re = /(["<>\[\]`^{}])/
40
+ while re =~ url
41
+ match = $~[1]
42
+ url = url.sub(re, sprintf("%%%x", match.ord))
43
+ end
78
44
  end
79
45
 
80
46
  # Excel limits escaped URL to 255 characters.
81
47
  if url.bytesize > 255
82
48
  raise "URL '#{url}' > 255 characters, it exceeds Excel's limit for URLS."
83
49
  end
50
+
84
51
  @url = url
85
- @link_type = link_type
86
52
  @str = str
87
- @url_str = url_str
53
+ @url_str = nil
88
54
  end
89
55
 
90
56
  def write_external_attributes(row, col, id)
91
57
  ref = xl_rowcol_to_cell(row, col)
92
58
 
93
- attributes = ['ref', ref]
94
- attributes += r_id_attributes(id)
59
+ attributes = [ ['ref', ref] ]
60
+ attributes << r_id_attributes(id)
95
61
 
96
- attributes << 'location' << url_str if url_str
97
- attributes << 'display' << display if display
98
- attributes << 'tooltip' << tip if tip
62
+ attributes << ['location', url_str] if url_str
63
+ attributes << ['display', display] if display
64
+ attributes << ['tooltip', tip] if tip
99
65
  attributes
100
66
  end
101
67
 
102
68
  def write_internal_attributes(row, col)
103
69
  ref = xl_rowcol_to_cell(row, col)
104
70
 
105
- attributes = ['ref', ref, 'location', url]
71
+ attributes = [
72
+ ['ref', ref],
73
+ ['location', url]
74
+ ]
75
+
76
+ attributes << ['tooltip', tip] if tip
77
+ attributes << ['display', str]
78
+ end
79
+ end
80
+
81
+ class InternalHyperlink < Hyperlink
82
+ def initialize(url, str)
83
+ @link_type = 2
84
+ @url = url.sub(/^internal:/, '')
85
+
86
+ # The displayed string defaults to the url string.
87
+ str ||= @url.dup
88
+
89
+ # Strip the mailto header.
90
+ @str = str.sub(/^mailto:/, '')
91
+
92
+ # Copy string for use in hyperlink elements.
93
+ @url_str = @str.dup
94
+
95
+ # Excel limits escaped URL to 255 characters.
96
+ if @url.bytesize > 255
97
+ raise "URL '#{@url}' > 255 characters, it exceeds Excel's limit for URLS."
98
+ end
99
+ end
100
+ end
101
+
102
+ class ExternalHyperlink < Hyperlink
103
+ def initialize(url, str = nil)
104
+ @link_type = 1
105
+
106
+ # Remove the URI scheme from internal links.
107
+ url = url.sub(/^external:/, '')
108
+
109
+ # The displayed string defaults to the url string.
110
+ str ||= url.dup
106
111
 
107
- attributes << 'tooltip' << tip if tip
108
- attributes << 'display' << str
112
+ # For external links change the directory separator from Unix to Dos.
113
+ url = url.gsub(%r|/|, '\\')
114
+ str.gsub!(%r|/|, '\\')
115
+
116
+ # Strip the mailto header.
117
+ str.sub!(/^mailto:/, '')
118
+
119
+ # External Workbook links need to be modified into the right format.
120
+ # The URL will look something like 'c:\temp\file.xlsx#Sheet!A1'.
121
+ # We need the part to the left of the # as the URL and the part to
122
+ # the right as the "location" string (if it exists).
123
+ url, url_str = url.split(/#/)
124
+
125
+ # Add the file:/// URI to the url if non-local.
126
+ if url =~ %r![:]! || # Windows style "C:/" link.
127
+ url =~ %r!^\\\\! # Network share.
128
+ url = "file:///#{url}"
129
+ end
130
+
131
+ # Convert a ./dir/file.xlsx link to dir/file.xlsx.
132
+ url = url.sub(%r!^.\\!, '')
133
+
134
+ # Excel limits escaped URL to 255 characters.
135
+ if url.bytesize > 255
136
+ raise "URL '#{url}' > 255 characters, it exceeds Excel's limit for URLS."
137
+ end
138
+ @url = url
139
+ @str = str
140
+ @url_str = url_str
109
141
  end
110
142
  end
111
143
  end
@@ -95,18 +95,19 @@ def write_page_setup(writer) #:nodoc:
95
95
  return unless @page_setup_changed
96
96
 
97
97
  attributes = []
98
- attributes << 'paperSize' << @paper_size if @paper_size
99
- attributes << 'scale' << @scale if @scale != 100
100
- attributes << 'fitToWidth' << @fit_width if @fit_page && @fit_width != 1
101
- attributes << 'fitToHeight' << @fit_height if @fit_page && @fit_height != 1
102
- attributes << 'pageOrder' << "overThenDown" if @across
103
- attributes << 'orientation'
104
- if @orientation
105
- attributes << 'portrait'
106
- else
107
- attributes << 'landscape'
108
- end
109
- attributes << 'useFirstPageNumber' << @page_start if ptrue?(@page_start)
98
+ attributes << ['paperSize', @paper_size] if @paper_size
99
+ attributes << ['scale', @scale] if @scale != 100
100
+ attributes << ['fitToWidth', @fit_width] if @fit_page && @fit_width != 1
101
+ attributes << ['fitToHeight', @fit_height] if @fit_page && @fit_height != 1
102
+ attributes << ['pageOrder', "overThenDown"] if @across
103
+ attributes << ['orientation',
104
+ if @orientation
105
+ 'portrait'
106
+ else
107
+ 'landscape'
108
+ end
109
+ ]
110
+ attributes << ['useFirstPageNumber', @page_start] if ptrue?(@page_start)
110
111
 
111
112
  writer.empty_tag('pageSetup', attributes)
112
113
  end
@@ -125,10 +126,10 @@ def write_print_options(writer) #:nodoc:
125
126
  return unless @print_options_changed
126
127
 
127
128
  attributes = []
128
- attributes << 'horizontalCentered' << 1 if @hcenter
129
- attributes << 'verticalCentered' << 1 if @vcenter
130
- attributes << 'headings' << 1 if @print_headers
131
- attributes << 'gridLines' << 1 if @print_gridlines
129
+ attributes << ['horizontalCentered', 1] if @hcenter
130
+ attributes << ['verticalCentered', 1] if @vcenter
131
+ attributes << ['headings', 1] if @print_headers
132
+ attributes << ['gridLines', 1] if @print_gridlines
132
133
  writer.empty_tag('printOptions', attributes)
133
134
  end
134
135
 
@@ -162,12 +163,12 @@ def write_odd_footer(writer) #:nodoc:
162
163
 
163
164
  def margin_attributes # :nodoc:
164
165
  [
165
- 'left', @margin_left,
166
- 'right', @margin_right,
167
- 'top', @margin_top,
168
- 'bottom', @margin_bottom,
169
- 'header', @margin_header,
170
- 'footer', @margin_footer
166
+ ['left', @margin_left],
167
+ ['right', @margin_right],
168
+ ['top', @margin_top],
169
+ ['bottom', @margin_bottom],
170
+ ['header', @margin_header],
171
+ ['footer', @margin_footer]
171
172
  ]
172
173
  end
173
174
  end
@@ -12,9 +12,9 @@ def test_write_a_latin
12
12
 
13
13
  result = @chart.__send__('write_a_latin',
14
14
  [
15
- 'typeface', 'Arial',
16
- 'pitchFamily', 34,
17
- 'charset', 0
15
+ ['typeface', 'Arial'],
16
+ ['pitchFamily', 34],
17
+ ['charset', 0]
18
18
  ]
19
19
  )
20
20
  assert_equal(expected, result)
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area01
13
+ def test_chart_font01
14
14
  @xlsx = 'chart_font01.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area02
13
+ def test_chart_font02
14
14
  @xlsx = 'chart_font02.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area03
13
+ def test_chart_font03
14
14
  @xlsx = 'chart_font03.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area04
13
+ def test_chart_font04
14
14
  @xlsx = 'chart_font04.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area05
13
+ def test_chart_font05
14
14
  @xlsx = 'chart_font05.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -10,7 +10,7 @@ def teardown
10
10
  File.delete(@xlsx) if File.exist?(@xlsx)
11
11
  end
12
12
 
13
- def test_chart_area06
13
+ def test_chart_font06
14
14
  @xlsx = 'chart_font06.xlsx'
15
15
  workbook = WriteXLSX.new(@xlsx)
16
16
  worksheet = workbook.add_worksheet
@@ -32,7 +32,7 @@ def test_start_end_tag
32
32
 
33
33
  def test_attribute
34
34
  assert_equal(
35
- "<foo x=\"1&gt;2\"/>", @obj.empty_tag("foo", ['x', '1>2'])
35
+ "<foo x=\"1&gt;2\"/>", @obj.empty_tag("foo", [ ['x', '1>2'] ])
36
36
  )
37
37
  end
38
38
 
@@ -52,8 +52,8 @@ def test_data_element_with_empty_attr
52
52
 
53
53
  def test_data_element
54
54
  attributes = [
55
- 'name', '_xlnm.Print_Titles',
56
- 'localSheetId', 0
55
+ ['name', '_xlnm.Print_Titles'],
56
+ ['localSheetId', 0]
57
57
  ]
58
58
  expected =
59
59
  "<definedName name=\"_xlnm.Print_Titles\" localSheetId=\"0\">Sheet1!$1:$1</definedName>"
@@ -10,7 +10,7 @@ def setup
10
10
  end
11
11
 
12
12
  def test_write_hyperlink_external
13
- hyperlink = Writexlsx::Worksheet::Hyperlink.new('')
13
+ hyperlink = Writexlsx::Worksheet::Hyperlink.factory('')
14
14
  @worksheet.__send__('write_hyperlink_external', hyperlink, 0, 0, 1)
15
15
  result = @worksheet.instance_variable_get(:@writer).string
16
16
  expected = '<hyperlink ref="A1" r:id="rId1"/>'
@@ -18,7 +18,7 @@ def test_write_hyperlink_external
18
18
  end
19
19
 
20
20
  def test_write_hyperlink_internal_sheet2
21
- hyperlink = Writexlsx::Worksheet::Hyperlink.new('internal:Sheet2!A1', 'Sheet2!A1')
21
+ hyperlink = Writexlsx::Worksheet::Hyperlink.factory('internal:Sheet2!A1', 'Sheet2!A1')
22
22
  @worksheet.__send__('write_hyperlink_internal', hyperlink, 0, 0)
23
23
  result = @worksheet.instance_variable_get(:@writer).string
24
24
  expected = '<hyperlink ref="A1" location="Sheet2!A1" display="Sheet2!A1"/>'
@@ -26,7 +26,7 @@ def test_write_hyperlink_internal_sheet2
26
26
  end
27
27
 
28
28
  def test_write_hyperlink_internal_quoted_sheet
29
- hyperlink = Writexlsx::Worksheet::Hyperlink.new("internal:'Data Sheet'!D5", "'Data Sheet'!D5")
29
+ hyperlink = Writexlsx::Worksheet::Hyperlink.factory("internal:'Data Sheet'!D5", "'Data Sheet'!D5")
30
30
  @worksheet.__send__('write_hyperlink_internal', hyperlink, 4, 0)
31
31
  result = @worksheet.instance_variable_get(:@writer).string
32
32
  expected = %q{<hyperlink ref="A5" location="'Data Sheet'!D5" display="'Data Sheet'!D5"/>}
@@ -34,7 +34,7 @@ def test_write_hyperlink_internal_quoted_sheet
34
34
  end
35
35
 
36
36
  def test_write_hyperlink_internal_tooltip
37
- hyperlink = Writexlsx::Worksheet::Hyperlink.new('internal:Sheet2!A1', 'Sheet2!A1')
37
+ hyperlink = Writexlsx::Worksheet::Hyperlink.factory('internal:Sheet2!A1', 'Sheet2!A1')
38
38
  hyperlink.tip = 'Screen Tip 1'
39
39
  @worksheet.__send__('write_hyperlink_internal', hyperlink, 17, 0)
40
40
  result = @worksheet.instance_variable_get(:@writer).string