caxlsx 3.0.0 → 3.1.0

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -31
  3. data/README.md +78 -170
  4. data/examples/{image1.jpeg → assets/image1.jpeg} +0 -0
  5. data/examples/generate.rb +15 -0
  6. data/lib/axlsx.rb +2 -3
  7. data/lib/axlsx/drawing/bar_chart.rb +3 -3
  8. data/lib/axlsx/drawing/bar_series.rb +3 -5
  9. data/lib/axlsx/drawing/d_lbls.rb +1 -1
  10. data/lib/axlsx/drawing/pie_series.rb +1 -1
  11. data/lib/axlsx/drawing/series_title.rb +3 -1
  12. data/lib/axlsx/drawing/title.rb +3 -2
  13. data/lib/axlsx/package.rb +53 -19
  14. data/lib/axlsx/rels/relationship.rb +26 -25
  15. data/lib/axlsx/stylesheet/font.rb +10 -2
  16. data/lib/axlsx/util/constants.rb +2 -1
  17. data/lib/axlsx/util/mime_type_utils.rb +1 -1
  18. data/lib/axlsx/util/validators.rb +2 -2
  19. data/lib/axlsx/util/zip_command.rb +73 -0
  20. data/lib/axlsx/version.rb +1 -1
  21. data/lib/axlsx/workbook/workbook.rb +0 -9
  22. data/lib/axlsx/workbook/worksheet/cell.rb +32 -5
  23. data/lib/axlsx/workbook/worksheet/col.rb +8 -4
  24. data/lib/axlsx/workbook/worksheet/data_validation.rb +4 -4
  25. data/lib/axlsx/workbook/worksheet/pivot_table.rb +7 -2
  26. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +1 -1
  27. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +1 -1
  28. data/lib/axlsx/workbook/worksheet/row.rb +6 -3
  29. data/lib/axlsx/workbook/worksheet/table.rb +1 -1
  30. data/lib/axlsx/workbook/worksheet/worksheet.rb +17 -4
  31. data/lib/caxlsx.rb +2 -0
  32. data/test/drawing/tc_drawing.rb +2 -2
  33. data/test/drawing/tc_hyperlink.rb +1 -1
  34. data/test/drawing/tc_one_cell_anchor.rb +1 -1
  35. data/test/drawing/tc_pic.rb +4 -4
  36. data/test/drawing/tc_pie_series.rb +2 -1
  37. data/test/drawing/tc_series_title.rb +21 -0
  38. data/test/drawing/tc_title.rb +16 -0
  39. data/test/fixtures/image1.gif +0 -0
  40. data/test/fixtures/image1.jpeg +0 -0
  41. data/test/fixtures/image1.jpg +0 -0
  42. data/test/fixtures/image1.png +0 -0
  43. data/test/fixtures/image1_fake.jpg +0 -0
  44. data/test/rels/tc_relationship.rb +8 -0
  45. data/test/stylesheet/tc_font.rb +14 -2
  46. data/test/stylesheet/tc_styles.rb +27 -1
  47. data/test/tc_axlsx.rb +6 -0
  48. data/test/tc_helper.rb +0 -2
  49. data/test/tc_package.rb +82 -13
  50. data/test/util/tc_mime_type_utils.rb +1 -1
  51. data/test/util/tc_validators.rb +1 -1
  52. data/test/workbook/worksheet/tc_cell.rb +68 -2
  53. data/test/workbook/worksheet/tc_col.rb +16 -1
  54. data/test/workbook/worksheet/tc_pivot_table.rb +8 -0
  55. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +8 -0
  56. data/test/workbook/worksheet/tc_rich_text_run.rb +3 -2
  57. data/test/workbook/worksheet/tc_row.rb +38 -0
  58. data/test/workbook/worksheet/tc_table.rb +10 -0
  59. data/test/workbook/worksheet/tc_worksheet.rb +24 -15
  60. metadata +130 -151
  61. data/examples/2010_comments.rb +0 -17
  62. data/examples/anchor_swapping.rb +0 -28
  63. data/examples/auto_filter.rb +0 -25
  64. data/examples/basic_charts.rb +0 -58
  65. data/examples/chart_colors.rb +0 -88
  66. data/examples/colored_links.rb +0 -59
  67. data/examples/conditional_formatting/example_conditional_formatting.rb +0 -89
  68. data/examples/conditional_formatting/getting_barred.rb +0 -37
  69. data/examples/conditional_formatting/hitting_the_high_notes.rb +0 -37
  70. data/examples/conditional_formatting/scaled_colors.rb +0 -39
  71. data/examples/conditional_formatting/stop_and_go.rb +0 -37
  72. data/examples/data_validation.rb +0 -67
  73. data/examples/example.rb +0 -885
  74. data/examples/extractive.rb +0 -45
  75. data/examples/ios_preview.rb +0 -14
  76. data/examples/merge_cells.rb +0 -17
  77. data/examples/no_grid_with_borders.rb +0 -18
  78. data/examples/page_setup.rb +0 -11
  79. data/examples/pivot_table.rb +0 -39
  80. data/examples/pivot_test.rb +0 -63
  81. data/examples/sheet_protection.rb +0 -10
  82. data/examples/skydrive/real_example.rb +0 -63
  83. data/examples/split.rb +0 -16
  84. data/examples/styles.rb +0 -66
  85. data/examples/underline.rb +0 -13
  86. data/examples/wrap_text.rb +0 -21
  87. data/lib/axlsx/util/parser.rb +0 -44
@@ -0,0 +1,73 @@
1
+ # encoding: UTF-8
2
+ require 'open3'
3
+ require 'shellwords'
4
+
5
+ module Axlsx
6
+
7
+ # The ZipCommand class supports zipping the Excel file contents using
8
+ # a binary zip program instead of RubyZip's `Zip::OutputStream`.
9
+ #
10
+ # The methods provided here mimic `Zip::OutputStream` so that `ZipCommand` can
11
+ # be used as a drop-in replacement. Note that method signatures are not
12
+ # identical to `Zip::OutputStream`, they are only sufficiently close so that
13
+ # `ZipCommand` and `Zip::OutputStream` can be interchangeably used within
14
+ # `caxlsx`.
15
+ class ZipCommand
16
+ # Raised when the zip command exits with a non-zero status.
17
+ class ZipError < StandardError; end
18
+
19
+ def initialize(zip_command)
20
+ @current_file = nil
21
+ @files = []
22
+ @zip_command = zip_command
23
+ end
24
+
25
+ # Create a temporary directory for writing files to.
26
+ #
27
+ # The directory and its contents are removed at the end of the block.
28
+ def open(output, &block)
29
+ Dir.mktmpdir do |dir|
30
+ @dir = dir
31
+ block.call(self)
32
+ write_file
33
+ zip_parts(output)
34
+ end
35
+ end
36
+
37
+ # Closes the current entry and opens a new for writing.
38
+ def put_next_entry(entry)
39
+ write_file
40
+ @current_file = "#{@dir}/#{entry.name}"
41
+ @files << entry.name
42
+ FileUtils.mkdir_p(File.dirname(@current_file))
43
+ end
44
+
45
+ # Write to a buffer that will be written to the current entry
46
+ def write(content)
47
+ @buffer << content
48
+ end
49
+ alias << write
50
+
51
+ private
52
+
53
+ def write_file
54
+ if @current_file
55
+ @buffer.rewind
56
+ File.open(@current_file, "wb") { |f| f.write @buffer.read }
57
+ end
58
+ @current_file = nil
59
+ @buffer = StringIO.new
60
+ end
61
+
62
+ def zip_parts(output)
63
+ output = Shellwords.shellescape(File.absolute_path(output))
64
+ inputs = Shellwords.shelljoin(@files)
65
+ escaped_dir = Shellwords.shellescape(@dir)
66
+ command = "cd #{escaped_dir} && #{@zip_command} #{output} #{inputs}"
67
+ stdout_and_stderr, status = Open3.capture2e(command)
68
+ if !status.success?
69
+ raise(ZipError.new(stdout_and_stderr))
70
+ end
71
+ end
72
+ end
73
+ end
data/lib/axlsx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Axlsx
2
2
 
3
3
  # The current version
4
- VERSION = "3.0.0"
4
+ VERSION = "3.1.0"
5
5
  end
@@ -197,15 +197,6 @@ require 'axlsx/workbook/worksheet/selection.rb'
197
197
  @worksheets[index] if index
198
198
  end
199
199
 
200
- # lets come back to this later when we are ready for parsing.
201
- #def self.parse entry
202
- # io = entry.get_input_stream
203
- # w = self.new
204
- # w.parser_xml = Nokogiri::XML(io.read)
205
- # w.parse_string :date1904, "//xmlns:workbookPr/@date1904"
206
- # w
207
- #end
208
-
209
200
  # Creates a new Workbook
210
201
  # The recomended way to work with workbooks is via Package#workbook
211
202
  # @option options [Boolean] date1904. If this is not specified, date1904 is set to false. Office 2011 for Mac defaults to false.
@@ -12,7 +12,7 @@ module Axlsx
12
12
 
13
13
  # @param [Row] row The row this cell belongs to.
14
14
  # @param [Any] value The value associated with this cell.
15
- # @option options [Symbol] type The intended data type for this cell. If not specified the data type will be determined internally based on the vlue provided.
15
+ # @option options [Symbol] type The intended data type for this cell. If not specified the data type will be determined internally based on the value provided.
16
16
  # @option options [Integer] style The index of the cellXfs item to be applied to this cell. If not specified, the default style (0) will be applied.
17
17
  # @option options [String] font_name
18
18
  # @option options [Integer] charset
@@ -30,6 +30,10 @@ module Axlsx
30
30
  # @option options [String] color an 8 letter rgb specification
31
31
  # @option options [Number] formula_value The value to cache for a formula cell.
32
32
  # @option options [Symbol] scheme must be one of :none, major, :minor
33
+ # @option options [Boolean] escape_formulas - Whether to treat a value starting with an equal
34
+ # sign as formula (default) or as simple string.
35
+ # Allowing user generated data to be interpreted as formulas can be dangerous
36
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
33
37
  def initialize(row, value = nil, options = {})
34
38
  @row = row
35
39
  # Do not use instance vars if not needed to use less RAM
@@ -38,6 +42,8 @@ module Axlsx
38
42
  type = options.delete(:type) || cell_type_from_value(value)
39
43
  self.type = type unless type == :string
40
44
 
45
+ escape_formulas = options[:escape_formulas]
46
+ self.escape_formulas = escape_formulas unless escape_formulas.nil?
41
47
 
42
48
  val = options.delete(:style)
43
49
  self.style = val unless val.nil? || val == 0
@@ -102,6 +108,18 @@ module Axlsx
102
108
  self.value = @value unless !defined?(@value) || @value.nil?
103
109
  end
104
110
 
111
+ # Whether to treat a value starting with an equal
112
+ # sign as formula (default) or as simple string.
113
+ # Allowing user generated data to be interpreted as formulas can be dangerous
114
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
115
+ # @return [Boolean]
116
+ attr_reader :escape_formulas
117
+
118
+ def escape_formulas=(v)
119
+ Axlsx.validate_boolean(v)
120
+ @escape_formulas = v
121
+ end
122
+
105
123
  # The value of this cell.
106
124
  # @return [String, Integer, Float, Time, Boolean] casted value based on cell's type attribute.
107
125
  attr_reader :value
@@ -324,6 +342,8 @@ module Axlsx
324
342
  end
325
343
 
326
344
  def is_formula?
345
+ return false if escape_formulas
346
+
327
347
  type == :string && @value.to_s.start_with?(?=)
328
348
  end
329
349
 
@@ -353,6 +373,7 @@ module Axlsx
353
373
  # @return [Float]
354
374
  def autowidth
355
375
  return if is_formula? || value.nil?
376
+
356
377
  if contains_rich_text?
357
378
  string_width('', font_size) + value.autowidth
358
379
  elsif styles.cellXfs[style].alignment && styles.cellXfs[style].alignment.wrap_text
@@ -389,7 +410,7 @@ module Axlsx
389
410
  # - scaling is not linear as font sizes increase
390
411
  def string_width(string, font_size)
391
412
  font_scale = font_size / 10.0
392
- (string.to_s.count(Worksheet::THIN_CHARS) + 3.0) * font_scale
413
+ (string.to_s.size + 3) * font_scale
393
414
  end
394
415
 
395
416
  # we scale the font size if bold style is applied to either the style font or
@@ -430,9 +451,11 @@ module Axlsx
430
451
  :time
431
452
  elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
432
453
  :boolean
433
- elsif v.to_s =~ Axlsx::NUMERIC_REGEX
454
+ elsif v.to_s =~ Axlsx::NUMERIC_REGEX && v.respond_to?(:to_i)
434
455
  :integer
435
- elsif v.to_s =~ Axlsx::FLOAT_REGEX
456
+ elsif v.to_s =~ Axlsx::SAFE_FLOAT_REGEX && v.respond_to?(:to_f)
457
+ :float
458
+ elsif (matchdata = v.to_s.match(MAYBE_FLOAT_REGEX)) && (Float::MIN_10_EXP..Float::MAX_10_EXP).cover?(matchdata[:exp].to_i) && v.respond_to?(:to_f)
436
459
  :float
437
460
  elsif v.to_s =~ Axlsx::ISO_8601_REGEX
438
461
  :iso_8601
@@ -452,7 +475,11 @@ module Axlsx
452
475
  case type
453
476
  when :date
454
477
  self.style = STYLE_DATE if self.style == 0
455
- v
478
+ if !v.is_a?(Date) && v.respond_to?(:to_date)
479
+ v.to_date
480
+ else
481
+ v
482
+ end
456
483
  when :time
457
484
  self.style = STYLE_DATE if self.style == 0
458
485
  if !v.is_a?(Time) && v.respond_to?(:to_time)
@@ -4,6 +4,10 @@ module Axlsx
4
4
  # The Col class defines column attributes for columns in sheets.
5
5
  class Col
6
6
 
7
+ # Maximum column width limit in MS Excel is 255 characters
8
+ # https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3
9
+ MAX_WIDTH = 255
10
+
7
11
  include Axlsx::OptionsParser
8
12
  include Axlsx::SerializedAttributes
9
13
  # Create a new Col objects
@@ -111,10 +115,10 @@ module Axlsx
111
115
  # TODO!!!
112
116
  #Axlsx.validate_unsigned_numeric(v) unless v == nil
113
117
  @custom_width = @best_fit = v != nil
114
- @width = v
118
+ @width = v.nil? ? v : [v, MAX_WIDTH].min
115
119
  end
116
120
 
117
- # updates the width for this col based on the cells autowidth and
121
+ # updates the width for this col based on the cells autowidth and
118
122
  # an optionally specified fixed width
119
123
  # @param [Cell] cell The cell to use in updating this col's width
120
124
  # @param [Integer] fixed_width If this is specified the width is set
@@ -127,8 +131,8 @@ module Axlsx
127
131
  elsif use_autowidth
128
132
  cell_width = cell.autowidth
129
133
  self.width = cell_width unless (width || 0) > (cell_width || 0)
130
- end
131
- end
134
+ end
135
+ end
132
136
 
133
137
  # Serialize this columns data to an xml string
134
138
  # @param [String] str
@@ -171,7 +171,7 @@ module Axlsx
171
171
  def formula1=(v); Axlsx::validate_string(v); @formula1 = v end
172
172
 
173
173
  # @see formula2
174
- def formula2=(v); Axlsx::validate_string(v); @formula2 = v end
174
+ def formula2=(v); Axlsx::validate_string(v); @formula2 = v end
175
175
 
176
176
  # @see allowBlank
177
177
  def allowBlank=(v); Axlsx::validate_boolean(v); @allowBlank = v end
@@ -216,8 +216,8 @@ module Axlsx
216
216
  valid_attributes = get_valid_attributes
217
217
 
218
218
  str << '<dataValidation '
219
- str << instance_values.map do |key, value|
220
- '' << key << '="' << Axlsx.booleanize(value).to_s << '"' if (valid_attributes.include?(key.to_sym) && !CHILD_ELEMENTS.include?(key.to_sym))
219
+ str << instance_values.map do |key, value|
220
+ '' << key << '="' << Axlsx.booleanize(value).to_s << '"' if (valid_attributes.include?(key.to_sym) && !CHILD_ELEMENTS.include?(key.to_sym))
221
221
  end.join(' ')
222
222
  str << '>'
223
223
  str << ('<formula1>' << self.formula1 << '</formula1>') if @formula1 and valid_attributes.include?(:formula1)
@@ -229,7 +229,7 @@ module Axlsx
229
229
  def get_valid_attributes
230
230
  attributes = [:allowBlank, :error, :errorStyle, :errorTitle, :prompt, :promptTitle, :showErrorMessage, :showInputMessage, :sqref, :type ]
231
231
 
232
- if [:whole, :decimal, :data, :time, :textLength].include?(@type)
232
+ if [:whole, :decimal, :data, :time, :date, :textLength].include?(@type)
233
233
  attributes << [:operator, :formula1]
234
234
  attributes << [:formula2] if [:between, :notBetween].include?(@operator)
235
235
  elsif @type == :list
@@ -111,8 +111,12 @@ module Axlsx
111
111
  if data_field.is_a? String
112
112
  data_field = {:ref => data_field}
113
113
  end
114
- data_field.values.each do |value|
115
- DataTypeValidator.validate "#{self.class}.data[]", [String], value
114
+ data_field.each do |key, value|
115
+ if key == :num_fmt
116
+ DataTypeValidator.validate "#{self.class}.data[]", [Integer], value
117
+ else
118
+ DataTypeValidator.validate "#{self.class}.data[]", [String], value
119
+ end
116
120
  end
117
121
  @data << data_field
118
122
  end
@@ -212,6 +216,7 @@ module Axlsx
212
216
  data.each do |datum_value|
213
217
  # The correct name prefix in ["Sum","Average", etc...]
214
218
  str << "<dataField name='#{(datum_value[:subtotal]||'')} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'"
219
+ str << " numFmtId='#{datum_value[:num_fmt]}'" if datum_value[:num_fmt]
215
220
  str << " subtotal='#{datum_value[:subtotal]}' " if datum_value[:subtotal]
216
221
  str << "/>"
217
222
  end
@@ -53,7 +53,7 @@ module Axlsx
53
53
  str << '</cacheSource>'
54
54
  str << ( '<cacheFields count="' << pivot_table.header_cells_count.to_s << '">')
55
55
  pivot_table.header_cells.each do |cell|
56
- str << ( '<cacheField name="' << cell.value << '" numFmtId="0">')
56
+ str << ( '<cacheField name="' << cell.clean_value << '" numFmtId="0">')
57
57
  str << '<sharedItems count="0">'
58
58
  str << '</sharedItems>'
59
59
  str << '</cacheField>'
@@ -215,7 +215,7 @@ module Axlsx
215
215
  # - scaling is not linear as font sizes increase
216
216
  def string_width(string, font_size)
217
217
  font_scale = font_size / 10.0
218
- string.count(Worksheet::THIN_CHARS) * font_scale
218
+ string.size * font_scale
219
219
  end
220
220
 
221
221
  # we scale the font size if bold style is applied to either the style font or
@@ -25,11 +25,12 @@ module Axlsx
25
25
  # @option options [Array, Symbol] types
26
26
  # @option options [Array, Integer] style
27
27
  # @option options [Float] height the row's height (in points)
28
+ # @option options [Integer] offset - add empty columns before values
28
29
  # @see Row#array_to_cells
29
30
  # @see Cell
30
31
  def initialize(worksheet, values=[], options={})
31
32
  self.worksheet = worksheet
32
- super(Cell, nil, values.size)
33
+ super(Cell, nil, values.size + options[:offset].to_i)
33
34
  self.height = options.delete(:height)
34
35
  worksheet.rows << self
35
36
  array_to_cells(values, options)
@@ -147,13 +148,15 @@ module Axlsx
147
148
  # @option options [Array, Integer] style
148
149
  def array_to_cells(values, options={})
149
150
  DataTypeValidator.validate :array_to_cells, Array, values
150
- types, style, formula_values = options.delete(:types), options.delete(:style), options.delete(:formula_values)
151
+ types, style, formula_values, escape_formulas, offset = options.delete(:types), options.delete(:style), options.delete(:formula_values), options.delete(:escape_formulas), options.delete(:offset)
152
+ offset.to_i.times { |index| self[index] = Cell.new(self) } if offset
151
153
  values.each_with_index do |value, index|
152
154
  options[:style] = style.is_a?(Array) ? style[index] : style if style
153
155
  options[:type] = types.is_a?(Array) ? types[index] : types if types
156
+ options[:escape_formulas] = escape_formulas.is_a?(Array) ? escape_formulas[index] : escape_formulas if escape_formulas
154
157
  options[:formula_value] = formula_values[index] if formula_values.is_a?(Array)
155
158
 
156
- self[index] = Cell.new(self, value, options)
159
+ self[index + offset.to_i] = Cell.new(self, value, options)
157
160
  end
158
161
  end
159
162
  end
@@ -80,7 +80,7 @@ module Axlsx
80
80
  str << ('<autoFilter ref="' << @ref << '"/>')
81
81
  str << ('<tableColumns count="' << header_cells.length.to_s << '">')
82
82
  header_cells.each_with_index do |cell,index|
83
- str << ('<tableColumn id ="' << (index+1).to_s << '" name="' << cell.value << '"/>')
83
+ str << ('<tableColumn id ="' << (index+1).to_s << '" name="' << cell.clean_value << '"/>')
84
84
  end
85
85
  str << '</tableColumns>'
86
86
  table_style_info.to_xml_string(str)
@@ -5,9 +5,6 @@ module Axlsx
5
5
  class Worksheet
6
6
  include Axlsx::OptionsParser
7
7
  include Axlsx::SerializedAttributes
8
- # definition of characters which are less than the maximum width of 0-9 in the default font for use in String#count.
9
- # This is used for autowidth calculations
10
- THIN_CHARS = '^.acfijklrstxzFIJL()-'.freeze
11
8
 
12
9
  # Creates a new worksheet.
13
10
  # @note the recommended way to manage worksheets is Workbook#add_worksheet
@@ -390,6 +387,15 @@ module Axlsx
390
387
  # @example - use << alias
391
388
  # ws << [3, 4, 5], :types => [nil, :float]
392
389
  #
390
+ # @example - specify whether a row should escape formulas or not
391
+ # ws.add_row ['=IF(2+2=4,4,5)', 2, 3], :escape_formulas=>true
392
+ #
393
+ # @example - specify whether a certain cells in a row should escape formulas or not
394
+ # ws.add_row ['=IF(2+2=4,4,5)', '=IF(13+13=4,4,5)'], :escape_formulas=>[true, false]
395
+ #
396
+ # @example - add a column offset when adding a row (inserts 'n' blank, unstyled columns before data)
397
+ # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], offset: 3
398
+ #
393
399
  # @see Worksheet#column_widths
394
400
  # @return [Row]
395
401
  # @option options [Array] values
@@ -397,6 +403,11 @@ module Axlsx
397
403
  # @option options [Array, Integer] style
398
404
  # @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
399
405
  # @option options [Float] height the row's height (in points)
406
+ # @option options [Integer] offset - add empty columns before values
407
+ # @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
408
+ # sign as formula (default) or as simple string.
409
+ # Allowing user generated data to be interpreted as formulas can be dangerous
410
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
400
411
  def add_row(values=[], options={})
401
412
  row = Row.new(self, values, options)
402
413
  update_column_info row, options.delete(:widths)
@@ -656,7 +667,9 @@ module Axlsx
656
667
 
657
668
  def validate_sheet_name(name)
658
669
  DataTypeValidator.validate :worksheet_name, String, name
659
- raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.size > 31
670
+ # ignore first character (BOM) after encoding to utf16 because Excel does so, too.
671
+ character_length = name.encode("utf-16")[1..-1].encode("utf-16").bytesize / 2
672
+ raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if character_length > 31
660
673
  raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char }
661
674
  name = Axlsx::coder.encode(name)
662
675
  sheet_names = @workbook.worksheets.reject { |s| s == self }.map { |s| s.name }
data/lib/caxlsx.rb ADDED
@@ -0,0 +1,2 @@
1
+ # encoding: UTF-8
2
+ require 'axlsx.rb'
@@ -23,7 +23,7 @@ class TestDrawing < Test::Unit::TestCase
23
23
  end
24
24
 
25
25
  def test_add_image
26
- src = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
26
+ src = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
27
27
  image = @ws.add_image(:image_src => src, :start_at=>[0,0], :width=>600, :height=>400)
28
28
  assert(@ws.drawing.anchors.last.is_a?(Axlsx::OneCellAnchor))
29
29
  assert(image.is_a?(Axlsx::Pic))
@@ -31,7 +31,7 @@ class TestDrawing < Test::Unit::TestCase
31
31
  assert_equal(400, image.height)
32
32
  end
33
33
  def test_add_two_cell_anchor_image
34
- src = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
34
+ src = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
35
35
  image = @ws.add_image(:image_src => src, :start_at=>[0,0], :end_at => [15,0])
36
36
  assert(@ws.drawing.anchors.last.is_a?(Axlsx::TwoCellAnchor))
37
37
  assert(image.is_a?(Axlsx::Pic))
@@ -5,7 +5,7 @@ class TestHyperlink < Test::Unit::TestCase
5
5
  def setup
6
6
  @p = Axlsx::Package.new
7
7
  ws = @p.workbook.add_worksheet
8
- @test_img = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
8
+ @test_img = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
9
9
  @image = ws.add_image :image_src => @test_img, :hyperlink => "http://axlsx.blogspot.com"
10
10
  @hyperlink = @image.hyperlink
11
11
  end
@@ -5,7 +5,7 @@ class TestOneCellAnchor < Test::Unit::TestCase
5
5
  def setup
6
6
  @p = Axlsx::Package.new
7
7
  @ws = @p.workbook.add_worksheet
8
- @test_img = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
8
+ @test_img = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
9
9
  @image = @ws.add_image :image_src => @test_img
10
10
  @anchor = @image.anchor
11
11
  end
@@ -5,10 +5,10 @@ class TestPic < Test::Unit::TestCase
5
5
  def setup
6
6
  @p = Axlsx::Package.new
7
7
  ws = @p.workbook.add_worksheet
8
- @test_img = @test_img_jpg = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
9
- @test_img_png = File.dirname(__FILE__) + "/../../examples/image1.png"
10
- @test_img_gif = File.dirname(__FILE__) + "/../../examples/image1.gif"
11
- @test_img_fake = File.dirname(__FILE__) + "/../../examples/image1_fake.jpg"
8
+ @test_img = @test_img_jpg = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
9
+ @test_img_png = File.dirname(__FILE__) + "/../fixtures/image1.png"
10
+ @test_img_gif = File.dirname(__FILE__) + "/../fixtures/image1.gif"
11
+ @test_img_fake = File.dirname(__FILE__) + "/../fixtures/image1_fake.jpg"
12
12
  @image = ws.add_image :image_src => @test_img, :hyperlink => 'https://github.com/randym', :tooltip => "What's up doc?", :opacity => 5
13
13
  end
14
14