axlsx 1.3.3 → 1.3.4

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 (73) hide show
  1. data/CHANGELOG.md +14 -0
  2. data/README.md +15 -15
  3. data/Rakefile +1 -1
  4. data/examples/example.rb +106 -35
  5. data/examples/wrap_text.rb +21 -0
  6. data/lib/axlsx/drawing/chart.rb +1 -1
  7. data/lib/axlsx/rels/relationship.rb +1 -1
  8. data/lib/axlsx/util/serialized_attributes.rb +32 -1
  9. data/lib/axlsx/util/validators.rb +1 -0
  10. data/lib/axlsx/version.rb +1 -1
  11. data/lib/axlsx/workbook/workbook.rb +1 -0
  12. data/lib/axlsx/workbook/worksheet/cell.rb +5 -2
  13. data/lib/axlsx/workbook/worksheet/cfvos.rb +0 -3
  14. data/lib/axlsx/workbook/worksheet/color_scale.rb +56 -16
  15. data/lib/axlsx/workbook/worksheet/data_bar.rb +42 -18
  16. data/lib/axlsx/workbook/worksheet/header_footer.rb +54 -0
  17. data/lib/axlsx/workbook/worksheet/worksheet.rb +29 -11
  18. data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +1 -1
  19. data/test/benchmark.rb +1 -2
  20. data/test/example.xlsx +0 -0
  21. data/test/profile.rb +4 -13
  22. data/test/rels/tc_relationship.rb +5 -0
  23. data/test/tc_helper.rb +5 -1
  24. data/test/workbook/worksheet/tc_color_scale.rb +31 -2
  25. data/test/workbook/worksheet/tc_data_bar.rb +7 -0
  26. data/test/workbook/worksheet/tc_header_footer.rb +151 -0
  27. data/test/workbook/worksheet/tc_worksheet.rb +31 -6
  28. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +1 -1
  29. metadata +11 -49
  30. data/examples/doc/_index.html +0 -88
  31. data/examples/doc/class_list.html +0 -53
  32. data/examples/doc/css/common.css +0 -1
  33. data/examples/doc/css/full_list.css +0 -57
  34. data/examples/doc/css/style.css +0 -328
  35. data/examples/doc/file_list.html +0 -52
  36. data/examples/doc/frames.html +0 -28
  37. data/examples/doc/index.html +0 -88
  38. data/examples/doc/js/app.js +0 -214
  39. data/examples/doc/js/full_list.js +0 -173
  40. data/examples/doc/js/jquery.js +0 -4
  41. data/examples/doc/method_list.html +0 -52
  42. data/examples/doc/top-level-namespace.html +0 -102
  43. data/examples/extractive.pdf +0 -0
  44. data/examples/finance.rb +0 -82
  45. data/examples/hyperlinks.rb +0 -23
  46. data/examples/image1.gif +0 -0
  47. data/examples/image1.jpg +0 -0
  48. data/examples/image1.png +0 -0
  49. data/examples/sample.png +0 -0
  50. data/examples/scraping_html.rb +0 -91
  51. data/examples/sheet_view.rb +0 -34
  52. data/examples/skydrive/axlsx.csv +0 -1
  53. data/examples/skydrive/axlsx.xlsx +0 -0
  54. data/examples/sprk2012/Screen Shot 2012-09-11 at 10.42.06 PM.png +0 -0
  55. data/examples/sprk2012/Screen Shot 2012-09-11 at 11.07.48 PM.png +0 -0
  56. data/examples/sprk2012/Screen Shot 2012-09-11 at 8.31.50 PM.png +0 -0
  57. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.23.27 PM.png +0 -0
  58. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.32.06 PM.png +0 -0
  59. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.33.35 PM.png +0 -0
  60. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.46.44 PM.png +0 -0
  61. data/examples/sprk2012/Screen Shot 2012-09-12 at 5.07.23 PM.png +0 -0
  62. data/examples/sprk2012/basics.rb +0 -11
  63. data/examples/sprk2012/basics.xlsx +0 -0
  64. data/examples/sprk2012/gravatar.jpeg +0 -0
  65. data/examples/sprk2012/hair_club.jpg +0 -0
  66. data/examples/sprk2012/images.rb +0 -9
  67. data/examples/sprk2012/images.xlsx +0 -0
  68. data/examples/sprk2012/line_chart.rb +0 -56
  69. data/examples/sprk2012/line_chart.xlsx +0 -0
  70. data/examples/sprk2012/sprk2012.key +0 -0
  71. data/examples/sprk2012/styles.rb +0 -20
  72. data/examples/sprk2012/styles.xlsx +0 -0
  73. data/examples/two_cell_anchor_image.rb +0 -11
@@ -145,6 +145,7 @@ module Axlsx
145
145
  RestrictionValidator.validate "cell run style u", [:none, :single, :double, :singleAccounting, :doubleAccounting], v
146
146
  end
147
147
 
148
+ # validates cell style family which must be between 1 and 5
148
149
  def self.validate_family(v)
149
150
  RestrictionValidator.validate "cell run style family", 1..5, v
150
151
  end
@@ -1,5 +1,5 @@
1
1
  module Axlsx
2
2
 
3
3
  # The current version
4
- VERSION = "1.3.3"
4
+ VERSION = "1.3.4"
5
5
  end
@@ -9,6 +9,7 @@ require 'axlsx/workbook/worksheet/cell.rb'
9
9
  require 'axlsx/workbook/worksheet/page_margins.rb'
10
10
  require 'axlsx/workbook/worksheet/page_set_up_pr.rb'
11
11
  require 'axlsx/workbook/worksheet/page_setup.rb'
12
+ require 'axlsx/workbook/worksheet/header_footer.rb'
12
13
  require 'axlsx/workbook/worksheet/print_options.rb'
13
14
  require 'axlsx/workbook/worksheet/cfvo.rb'
14
15
  require 'axlsx/workbook/worksheet/cfvos.rb'
@@ -398,8 +398,8 @@ module Axlsx
398
398
  end
399
399
 
400
400
  # assigns the owning row for this cell.
401
- def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
402
-
401
+ def row=(v) @row=v end
402
+
403
403
  # Determines the cell type based on the cell value.
404
404
  # @note This is only used when a cell is created but no :type option is specified, the following rules apply:
405
405
  # 1. If the value is an instance of Date, the type is set to :date
@@ -444,6 +444,9 @@ module Axlsx
444
444
  v ? 1 : 0
445
445
  else
446
446
  @type = :string
447
+ v.to_s
448
+ # TODO find a better way to do this as it accounts for 30% of
449
+ # processing time in benchmarking...
447
450
  ::CGI.escapeHTML(v.to_s)
448
451
  end
449
452
  end
@@ -6,9 +6,6 @@ module Axlsx
6
6
 
7
7
  def initialize
8
8
  super(Cfvo)
9
- @list << Cfvo.new(:type => :min, :val => 0)
10
- @list << Cfvo.new(:type => :max, :val => 0)
11
- lock
12
9
  end
13
10
 
14
11
  def to_xml_string(str='')
@@ -7,6 +7,35 @@ module Axlsx
7
7
  # @see ConditionalFormattingRule#initialize
8
8
  class ColorScale
9
9
 
10
+ class << self
11
+
12
+ # These are the default conditional formatting value objects
13
+ # that define a two tone color gradient.
14
+ def default_cfvos
15
+ [{:type => :min, :val => 0, :color => 'FFFF7128'},
16
+ {:type => :max, :val => 0, :color => 'FFFFEF9C'}]
17
+ end
18
+
19
+ # A builder for two tone color gradient
20
+ # @example
21
+ # # this creates a two tone color scale
22
+ # color_scale = Axlsx::ColorScale.two_tone
23
+ # @see examples/example.rb conditional formatting examples.
24
+ def two_tone
25
+ self.new
26
+ end
27
+
28
+ # A builder for three tone color gradient
29
+ # @example
30
+ # #this creates a three tone color scale
31
+ # color_scale = Axlsx::ColorScale.three_tone
32
+ # @see examples/example.rb conditional formatting examples.
33
+ def three_tone
34
+ self.new({:type => :min, :val => 0, :color => 'FFF8696B'},
35
+ {:type => :percent, :val => '50', :color => 'FFFFEB84'},
36
+ {:type => :max, :val => 0, :color => 'FF63BE7B'})
37
+ end
38
+ end
10
39
  # A simple typed list of cfvos
11
40
  # @return [SimpleTypedList]
12
41
  # @see Cfvo
@@ -17,25 +46,31 @@ module Axlsx
17
46
  # A simple types list of colors
18
47
  # @return [SimpleTypedList]
19
48
  # @see Color
20
- attr_reader :colors
49
+ def colors
50
+ @colors ||= SimpleTypedList.new Color
51
+ end
21
52
 
22
53
  # creates a new ColorScale object.
23
- # This method will yield it self so you can alter the properites of the defauls conditional formating value object (cfvo and colors
24
- # Two value objects and two colors are created on initialization and cannot be deleted.
25
54
  # @see Cfvo
26
55
  # @see Color
27
- def initialize
28
- initialize_colors
56
+ # @example
57
+ # color_scale = Axlsx::ColorScale.new({:type => :num, :val => 0.55, :color => 'fff7696c'})
58
+ def initialize(*cfvos)
59
+ initialize_default_cfvos(cfvos)
29
60
  yield self if block_given?
30
61
  end
31
62
 
32
63
  # adds a new cfvo / color pair to the color scale and returns a hash containing
33
64
  # a reference to the newly created cfvo and color objects so you can alter the default properties.
34
65
  # @return [Hash] a hash with :cfvo and :color keys referencing the newly added objects.
66
+ # @param [Hash] options options for the new cfvo and color objects
67
+ # @option [Symbol] type The type of cfvo you to add
68
+ # @option [Any] val The value of the cfvo to add
69
+ # @option [String] The rgb color for the cfvo
35
70
  def add(options={})
36
71
  value_objects << Cfvo.new(:type => options[:type] || :min, :val => options[:val] || 0)
37
- @colors << Color.new(:rgb => options[:color] || "FF000000")
38
- {:cfvo => value_objects.last, :color => @colors.last}
72
+ colors << Color.new(:rgb => options[:color] || "FF000000")
73
+ {:cfvo => value_objects.last, :color => colors.last}
39
74
  end
40
75
 
41
76
 
@@ -44,7 +79,7 @@ module Axlsx
44
79
  # @note you cannot remove the first two cfvo and color pairs
45
80
  def delete_at(index=2)
46
81
  value_objects.delete_at index
47
- @colors.delete_at index
82
+ colors.delete_at index
48
83
  end
49
84
 
50
85
  # Serialize this color_scale object data to an xml string
@@ -53,18 +88,23 @@ module Axlsx
53
88
  def to_xml_string(str = '')
54
89
  str << '<colorScale>'
55
90
  value_objects.to_xml_string(str)
56
- @colors.each { |color| color.to_xml_string(str) }
91
+ colors.each { |color| color.to_xml_string(str) }
57
92
  str << '</colorScale>'
58
93
  end
59
94
 
60
95
  private
61
-
62
- # creates the initial color objects
63
- def initialize_colors
64
- @colors = SimpleTypedList.new Color
65
- @colors.concat [Color.new(:rgb => "FFFF0000"), Color.new(:rgb => "FF0000FF")]
66
- @colors.lock
96
+ # There has got to be cleaner way of merging these arrays.
97
+ def initialize_default_cfvos(user_cfvos)
98
+ defaults = self.class.default_cfvos
99
+ user_cfvos.each_with_index do |cfvo, index|
100
+ if index < defaults.size
101
+ cfvo = defaults[index].merge(cfvo)
102
+ end
103
+ add cfvo
104
+ end
105
+ while colors.size < defaults.size
106
+ add defaults[colors.size - 1]
107
+ end
67
108
  end
68
-
69
109
  end
70
110
  end
@@ -10,16 +10,27 @@ module Axlsx
10
10
  include Axlsx::OptionsParser
11
11
  include Axlsx::SerializedAttributes
12
12
 
13
+ class << self
14
+ # This differs from ColorScale. There must be exactly two cfvos one color
15
+ def default_cfvos
16
+ [{:type => :min, :val => "0"},
17
+ {:type => :max, :val => "0"}]
18
+ end
19
+ end
20
+
13
21
  # Creates a new data bar conditional formatting object
22
+ # @param [Hash] options
14
23
  # @option options [Integer] minLength
15
24
  # @option options [Integer] maxLength
16
25
  # @option options [Boolean] showValue
17
26
  # @option options [String] color - the rbg value used to color the bars
18
- def initialize(options = {})
27
+ # @param [Array] cfvos hashes defining the gradient interpolation points for this formatting.
28
+ def initialize(options = {}, *cfvos)
19
29
  @min_length = 10
20
30
  @max_length = 90
21
31
  @show_value = true
22
32
  parse_options options
33
+ initialize_cfvos(cfvos)
23
34
  yield self if block_given?
24
35
  end
25
36
 
@@ -70,27 +81,27 @@ module Axlsx
70
81
  end
71
82
  alias :minLength= :min_length=
72
83
 
73
- # @see maxLength
74
- def max_length=(v)
75
- Axlsx.validate_unsigned_int(v)
76
- @max_length = v
77
- end
84
+ # @see maxLength
85
+ def max_length=(v)
86
+ Axlsx.validate_unsigned_int(v)
87
+ @max_length = v
88
+ end
78
89
  alias :maxLength= :max_length=
79
90
 
80
- # @see showValue
81
- def show_value=(v)
82
- Axlsx.validate_boolean(v)
83
- @show_value = v
84
- end
91
+ # @see showValue
92
+ def show_value=(v)
93
+ Axlsx.validate_boolean(v)
94
+ @show_value = v
95
+ end
85
96
  alias :showValue= :show_value=
86
97
 
87
- # Sets the color for the data bars.
88
- # @param [Color|String] v The color object, or rgb string value to apply
89
- def color=(v)
90
- @color = v if v.is_a? Color
91
- self.color.rgb = v if v.is_a? String
92
- @color
93
- end
98
+ # Sets the color for the data bars.
99
+ # @param [Color|String] v The color object, or rgb string value to apply
100
+ def color=(v)
101
+ @color = v if v.is_a? Color
102
+ self.color.rgb = v if v.is_a? String
103
+ @color
104
+ end
94
105
 
95
106
  # Serialize this object to an xml string
96
107
  # @param [String] str
@@ -103,5 +114,18 @@ module Axlsx
103
114
  self.color.to_xml_string(str)
104
115
  str << '</dataBar>'
105
116
  end
117
+
118
+ private
119
+
120
+ def initialize_cfvos(cfvos)
121
+ self.class.default_cfvos.each_with_index.map do |default, index|
122
+ if index < cfvos.size
123
+ value_objects << Cfvo.new(default.merge(cfvos[index]))
124
+ else
125
+ value_objects << Cfvo.new(default)
126
+ end
127
+ end
128
+ end
129
+
106
130
  end
107
131
  end
@@ -0,0 +1,54 @@
1
+ module Axlsx
2
+ # Header/Footer options for printing a worksheet. All settings are optional.
3
+ #
4
+ # Headers and footers are generated using a string which is a combination
5
+ # of plain text and control characters. A fairly comprehensive list of control
6
+ # characters can be found here:
7
+ # https://github.com/randym/axlsx/blob/master/notes_on_header_footer.md
8
+ #     
9
+ # @note The recommended way of managing header/footers is via Worksheet#header_footer
10
+ # @see Worksheet#initialize
11
+ class HeaderFooter
12
+
13
+ include Axlsx::OptionsParser
14
+ include Axlsx::SerializedAttributes
15
+ include Axlsx::Accessors
16
+
17
+ # Creates a new HeaderFooter object
18
+ # @option options [String] odd_header The content for headers on odd numbered pages.
19
+ # @option options [String] odd_footer The content for footers on odd numbered pages.
20
+ # @option options [String] even_header The content for headers on even numbered pages.
21
+ # @option options [String] even_footer The content for footers on even numbered pages.
22
+ # @option options [String] first_header The content for headers on even numbered pages.
23
+ # @option options [String] first_footer The content for footers on even numbered pages.
24
+ # @option options [Boolean] different_odd_even Setting this to true will show different headers/footers on odd and even pages. When false, the odd headers/footers are used on each page. (Default: false)
25
+ # @option options [Boolean] different_first If true, will use the first header/footer on page 1. Otherwise, the odd header/footer is used.
26
+ def initialize(options = {})
27
+ parse_options options
28
+ end
29
+
30
+ serializable_attributes :different_odd_even, :different_first
31
+ serializable_element_attributes :odd_header, :odd_footer, :even_header, :even_footer, :first_header, :first_footer
32
+ string_attr_accessor :odd_header, :odd_footer, :even_header, :even_footer, :first_header, :first_footer
33
+ boolean_attr_accessor :different_odd_even, :different_first
34
+
35
+ # Set some or all header/footers at once.
36
+ # @param [Hash] options The header/footer options to set (possible keys are :odd_header, :odd_footer, :even_header, :even_footer, :first_header, :first_footer, :different_odd_even, and :different_first).
37
+ def set(options)
38
+ parse_options options
39
+ end
40
+
41
+ # Serializes the header/footer object.
42
+ # @param [String] str
43
+ # @return [String]
44
+ def to_xml_string(str = '')
45
+ str << "<headerFooter "
46
+ serialized_attributes str
47
+ str << ">"
48
+ serialized_element_attributes(str) do |value|
49
+ value = ::CGI.escapeHTML(value)
50
+ end
51
+ str << "</headerFooter>"
52
+ end
53
+ end
54
+ end
@@ -9,7 +9,8 @@ module Axlsx
9
9
  # This is used for autowidth calculations
10
10
  # @return [String]
11
11
  def self.thin_chars
12
- @thin_chars ||= "^.acefijklrstxyzFIJL()-"
12
+ # removed 'e' and 'y' from this list - as a GUESS
13
+ @thin_chars ||= "^.acfijklrstxzFIJL()-"
13
14
  end
14
15
 
15
16
  # Creates a new worksheet.
@@ -18,6 +19,7 @@ module Axlsx
18
19
  # @option options [String] name The name of this worksheet.
19
20
  # @option options [Hash] page_margins A hash containing page margins for this worksheet. @see PageMargins
20
21
  # @option options [Hash] print_options A hash containing print options for this worksheet. @see PrintOptions
22
+ # @option options [Hash] header_footer A hash containing header/footer options for this worksheet. @see HeaderFooter
21
23
  # @option options [Boolean] show_gridlines indicates if gridlines should be shown for this sheet.
22
24
  def initialize(wb, options={})
23
25
  self.workbook = wb
@@ -34,6 +36,7 @@ module Axlsx
34
36
  @page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
35
37
  @page_setup = PageSetup.new options[:page_setup] if options[:page_setup]
36
38
  @print_options = PrintOptions.new options[:print_options] if options[:print_options]
39
+ @header_footer = HeaderFooter.new options[:header_footer] if options[:header_footer]
37
40
  end
38
41
 
39
42
  # The name of the worksheet
@@ -41,7 +44,7 @@ module Axlsx
41
44
  def name
42
45
  @name ||= "Sheet" + (index+1).to_s
43
46
  end
44
-
47
+
45
48
  # The sheet calculation properties
46
49
  # @return [SheetCalcPr]
47
50
  def sheet_calc_pr
@@ -104,7 +107,7 @@ module Axlsx
104
107
  # An range that excel will apply an autfilter to "A1:B3"
105
108
  # This will turn filtering on for the cells in the range.
106
109
  # The first row is considered the header, while subsequent rows are considerd to be data.
107
- # @return String
110
+ # @return String
108
111
  def auto_filter
109
112
  @auto_filter ||= AutoFilter.new self
110
113
  end
@@ -193,6 +196,21 @@ module Axlsx
193
196
  @print_options
194
197
  end
195
198
 
199
+ # Options for headers and footers.
200
+ # @example
201
+ # wb = Axlsx::Package.new.workbook
202
+ # # would generate something like: "file.xlsx : sheet_name 2 of 7 date with timestamp"
203
+ # header = {:different_odd_ => false, :odd_header => "&L&F : &A&C&Pof%N%R%D %T"}
204
+ # ws = wb.add_worksheet :header_footer => header
205
+ #
206
+ # @see HeaderFooter#initialize
207
+ # @return [HeaderFooter]
208
+ def header_footer
209
+ @header_footer ||= HeaderFooter.new
210
+ yield @header_footer if block_given?
211
+ @header_footer
212
+ end
213
+
196
214
  # convinience method to access all cells in this worksheet
197
215
  # @return [Array] cells
198
216
  def cells
@@ -280,7 +298,7 @@ module Axlsx
280
298
 
281
299
  # The name of the worksheet
282
300
  # The name of a worksheet must be unique in the workbook, and must not exceed 31 characters
283
- # @param [String] name
301
+ # @param [String] name
284
302
  def name=(name)
285
303
  validate_sheet_name name
286
304
  @name=Axlsx::coder.encode(name)
@@ -388,7 +406,7 @@ module Axlsx
388
406
  cf = ConditionalFormatting.new( :sqref => cells )
389
407
  cf.add_rules rules
390
408
  conditional_formattings << cf
391
- conditional_formattings
409
+ conditional_formattings
392
410
  end
393
411
 
394
412
  # Add data validation to this worksheet.
@@ -513,7 +531,7 @@ module Axlsx
513
531
  def sanitize(str)
514
532
  str.gsub(CONTROL_CHAR_REGEX, '')
515
533
  end
516
-
534
+
517
535
  # The worksheet relationships. This is managed automatically by the worksheet
518
536
  # @return [Relationships]
519
537
  def relationships
@@ -570,12 +588,12 @@ module Axlsx
570
588
 
571
589
 
572
590
  private
573
-
591
+
574
592
  def validate_sheet_name(name)
575
593
  DataTypeValidator.validate "Worksheet.name", String, name
576
594
  raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.size > 31
577
595
  raise ArgumentError, (ERR_SHEET_NAME_COLON_FORBIDDEN % name) if name.include? ':'
578
- name = Axlsx::coder.encode(name)
596
+ name = Axlsx::coder.encode(name)
579
597
  sheet_names = @workbook.worksheets.map { |s| s.name }
580
598
  raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % name) if sheet_names.include?(name)
581
599
  end
@@ -586,7 +604,7 @@ module Axlsx
586
604
  sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
587
605
  auto_filter, merged_cells, conditional_formattings,
588
606
  data_validations, hyperlinks, print_options, page_margins,
589
- page_setup, worksheet_drawing, worksheet_comments,
607
+ page_setup, header_footer, worksheet_drawing, worksheet_comments,
590
608
  tables]
591
609
  end
592
610
 
@@ -606,7 +624,7 @@ module Axlsx
606
624
  # @see Worksheet#protect_range
607
625
  # @return [SimpleTypedList] The protected ranges for this worksheet
608
626
  def protected_ranges
609
- @protected_ranges ||= ProtectedRanges.new self
627
+ @protected_ranges ||= ProtectedRanges.new self
610
628
  # SimpleTypedList.new ProtectedRange
611
629
  end
612
630
 
@@ -619,7 +637,7 @@ module Axlsx
619
637
  # data validations array
620
638
  # @return [Array]
621
639
  def data_validations
622
- @data_validations ||= DataValidations.new self
640
+ @data_validations ||= DataValidations.new self
623
641
  end
624
642
 
625
643
  # merged cells array