keeguon-spreadsheet 0.9.3

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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +619 -0
  3. data/Manifest.txt +85 -0
  4. data/bin/xlsopcodes +18 -0
  5. data/lib/parseexcel.rb +27 -0
  6. data/lib/parseexcel/parseexcel.rb +75 -0
  7. data/lib/parseexcel/parser.rb +11 -0
  8. data/lib/spreadsheet.rb +80 -0
  9. data/lib/spreadsheet/column.rb +71 -0
  10. data/lib/spreadsheet/compatibility.rb +23 -0
  11. data/lib/spreadsheet/datatypes.rb +161 -0
  12. data/lib/spreadsheet/encodings.rb +57 -0
  13. data/lib/spreadsheet/excel.rb +88 -0
  14. data/lib/spreadsheet/excel/error.rb +26 -0
  15. data/lib/spreadsheet/excel/internals.rb +458 -0
  16. data/lib/spreadsheet/excel/internals/biff5.rb +17 -0
  17. data/lib/spreadsheet/excel/internals/biff8.rb +19 -0
  18. data/lib/spreadsheet/excel/offset.rb +41 -0
  19. data/lib/spreadsheet/excel/password_hash.rb +24 -0
  20. data/lib/spreadsheet/excel/reader.rb +1302 -0
  21. data/lib/spreadsheet/excel/reader/biff5.rb +42 -0
  22. data/lib/spreadsheet/excel/reader/biff8.rb +231 -0
  23. data/lib/spreadsheet/excel/rgb.rb +122 -0
  24. data/lib/spreadsheet/excel/row.rb +98 -0
  25. data/lib/spreadsheet/excel/sst_entry.rb +46 -0
  26. data/lib/spreadsheet/excel/workbook.rb +80 -0
  27. data/lib/spreadsheet/excel/worksheet.rb +115 -0
  28. data/lib/spreadsheet/excel/writer.rb +1 -0
  29. data/lib/spreadsheet/excel/writer/biff8.rb +75 -0
  30. data/lib/spreadsheet/excel/writer/format.rb +264 -0
  31. data/lib/spreadsheet/excel/writer/n_worksheet.rb +888 -0
  32. data/lib/spreadsheet/excel/writer/workbook.rb +735 -0
  33. data/lib/spreadsheet/excel/writer/worksheet.rb +940 -0
  34. data/lib/spreadsheet/font.rb +115 -0
  35. data/lib/spreadsheet/format.rb +209 -0
  36. data/lib/spreadsheet/formula.rb +9 -0
  37. data/lib/spreadsheet/helpers.rb +11 -0
  38. data/lib/spreadsheet/link.rb +43 -0
  39. data/lib/spreadsheet/note.rb +23 -0
  40. data/lib/spreadsheet/noteObject.rb +17 -0
  41. data/lib/spreadsheet/row.rb +151 -0
  42. data/lib/spreadsheet/workbook.rb +143 -0
  43. data/lib/spreadsheet/worksheet.rb +326 -0
  44. data/lib/spreadsheet/writer.rb +30 -0
  45. data/test/data/test_adding_data_to_existing_file.xls +0 -0
  46. data/test/data/test_borders.xls +0 -0
  47. data/test/data/test_changes.xls +0 -0
  48. data/test/data/test_comment.xls +0 -0
  49. data/test/data/test_copy.xls +0 -0
  50. data/test/data/test_datetime.xls +0 -0
  51. data/test/data/test_empty.xls +0 -0
  52. data/test/data/test_formula.xls +0 -0
  53. data/test/data/test_long_sst_record.xls +0 -0
  54. data/test/data/test_margin.xls +0 -0
  55. data/test/data/test_merged_and_protected.xls +0 -0
  56. data/test/data/test_merged_cells.xls +0 -0
  57. data/test/data/test_missing_row.xls +0 -0
  58. data/test/data/test_pagesetup.xls +0 -0
  59. data/test/data/test_version_excel5.xls +0 -0
  60. data/test/data/test_version_excel95.xls +0 -0
  61. data/test/data/test_version_excel97.xls +0 -0
  62. data/test/data/test_version_excel97_2010.xls +0 -0
  63. data/test/data/test_worksheet_visibility.xls +0 -0
  64. data/test/excel/reader.rb +30 -0
  65. data/test/excel/row.rb +40 -0
  66. data/test/excel/writer/workbook.rb +95 -0
  67. data/test/excel/writer/worksheet.rb +81 -0
  68. data/test/font.rb +163 -0
  69. data/test/format.rb +95 -0
  70. data/test/integration.rb +1390 -0
  71. data/test/row.rb +33 -0
  72. data/test/suite.rb +18 -0
  73. data/test/workbook.rb +55 -0
  74. data/test/workbook_protection.rb +19 -0
  75. data/test/worksheet.rb +112 -0
  76. metadata +148 -0
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ require 'spreadsheet/datatypes'
3
+ require 'spreadsheet/encodings'
4
+
5
+ module Spreadsheet
6
+ ##
7
+ # Font formatting data
8
+ class Font
9
+ include Spreadsheet::Datatypes
10
+ include Spreadsheet::Encodings
11
+ attr_accessor :name
12
+ ##
13
+ # You can set the following boolean Font attributes
14
+ # * #italic
15
+ # * #strikeout
16
+ # * #outline
17
+ # * #shadow
18
+ boolean :italic, :strikeout, :outline, :shadow
19
+ ##
20
+ # Font color
21
+ colors :color
22
+ ##
23
+ # Font weight
24
+ # Valid values: :normal, :bold or any positive Integer.
25
+ # In Excel:
26
+ # 100 <= weight <= 1000
27
+ # :bold => 700
28
+ # :normal => 400
29
+ # Default: :normal
30
+ enum :weight, :normal, :bold, Integer, :bold => :b
31
+ ##
32
+ # Escapement
33
+ # Valid values: :normal, :superscript or :subscript.
34
+ # Default: :normal
35
+ enum :escapement, :normal, :superscript, :subscript,
36
+ :subscript => :sub,
37
+ :superscript => :super
38
+ # Font size
39
+ # Valid values: Any positive Integer.
40
+ # Default: 10
41
+ enum :size, 10, Numeric
42
+ # Underline type
43
+ # Valid values: :none, :single, :double, :single_accounting and
44
+ # :double_accounting.
45
+ # Default: :none
46
+ enum :underline, :none, :single, :double,
47
+ :single_accounting, :double_accounting,
48
+ :single => true
49
+ # Font Family
50
+ # Valid values: :none, :roman, :swiss, :modern, :script, :decorative
51
+ # Default: :none
52
+ enum :family, :none, :roman, :swiss, :modern, :script, :decorative
53
+ # Font Family
54
+ # Valid values: :default, :iso_latin1, :symbol, :apple_roman, :shift_jis,
55
+ # :korean_hangul, :korean_johab, :chinese_simplified,
56
+ # :chinese_traditional, :greek, :turkish, :vietnamese,
57
+ # :hebrew, :arabic, :cyrillic, :thai, :iso_latin2, :oem_latin1
58
+ # Default: :default
59
+ enum :encoding, :default, :iso_latin1, :symbol, :apple_roman, :shift_jis,
60
+ :korean_hangul, :korean_johab, :chinese_simplified,
61
+ :chinese_traditional, :greek, :turkish, :vietnamese,
62
+ :hebrew, :arabic, :baltic, :cyrillic, :thai, :iso_latin2,
63
+ :oem_latin1
64
+ def initialize name, opts={}
65
+ self.name = name
66
+ @color = :text
67
+ @previous_fast_key = nil
68
+ @size = nil
69
+ @weight = nil
70
+ @italic = nil
71
+ @strikeout = nil
72
+ @outline = nil
73
+ @shadow = nil
74
+ @escapement = nil
75
+ @underline = nil
76
+ @family = nil
77
+ @encoding = nil
78
+ opts.each do |key, val|
79
+ self.send "#{key}=", val
80
+ end
81
+ end
82
+ ##
83
+ # Sets #weight to :bold if(_bool_), :normal otherwise.
84
+ def bold= bool
85
+ self.weight = bool ? :bold : nil
86
+ end
87
+ def key # :nodoc:
88
+ fk = fast_key
89
+ return @key if @previous_fast_key == fk
90
+ @previous_fast_key = fk
91
+ @key = build_key
92
+ end
93
+ private
94
+ def build_key # :nodoc:
95
+ underscore = client('_', 'UTF-8')
96
+ key = []
97
+ key << @name
98
+ key << underscore << client(size.to_s, 'US-ASCII')
99
+ key << underscore << client(weight.to_s, 'US-ASCII')
100
+ key << client('_italic', 'UTF-8') if italic?
101
+ key << client('_strikeout', 'UTF-8') if strikeout?
102
+ key << client('_outline', 'UTF-8') if outline?
103
+ key << client('_shadow', 'UTF-8') if shadow?
104
+ key << underscore << client(escapement.to_s, 'US-ASCII')
105
+ key << underscore << client(underline.to_s, 'US-ASCII')
106
+ key << underscore << client(color.to_s, 'US-ASCII')
107
+ key << underscore << client(family.to_s, 'US-ASCII')
108
+ key << underscore << client(encoding.to_s, 'US-ASCII')
109
+ key.join("")
110
+ end
111
+ def fast_key
112
+ [@name, @size, @weight, @italic, @strikeout, @outline, @shadow, @escapement, @underline, @color, @family, @encoding]
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,209 @@
1
+ # encoding: utf-8
2
+ require 'spreadsheet/datatypes'
3
+ require 'spreadsheet/encodings'
4
+ require 'spreadsheet/font'
5
+
6
+ module Spreadsheet
7
+ ##
8
+ # Formatting data
9
+ class Format
10
+ include Spreadsheet::Datatypes
11
+ include Spreadsheet::Encodings
12
+ ##
13
+ # You can set the following boolean attributes:
14
+ # #cross_down:: Draws a Line from the top-left to the bottom-right
15
+ # corner of a cell.
16
+ # #cross_up:: Draws a Line from the bottom-left to the top-right
17
+ # corner of a cell.
18
+ # #hidden:: The cell is hidden.
19
+ # #locked:: The cell is locked.
20
+ # #merge_range:: The cell is in a merged range.
21
+ # #shrink:: Shrink the contents to fit the cell.
22
+ # #text_justlast:: Force the last line of a cell to be justified. This
23
+ # probably makes sense if horizontal_align = :justify
24
+ # #left:: Apply a border style to the left of the cell.
25
+ # #right:: Apply a border style to the right of the cell.
26
+ # #top:: Apply a border style at the top of the cell.
27
+ # #bottom:: Apply a border style at the bottom of the cell.
28
+ # #rotation_stacked:: Characters in the cell are stacked on top of each
29
+ # other. Excel will ignore other rotation values if
30
+ # this is set.
31
+ boolean :cross_down, :cross_up, :hidden, :locked,
32
+ :merge_range, :shrink, :text_justlast, :text_wrap,
33
+ :rotation_stacked
34
+ ##
35
+ # Border line styles
36
+ # Valid values: :none, :thin, :medium, :dashed, :dotted, :thick,
37
+ # :double, :hair, :medium_dashed, :thin_dash_dotted,
38
+ # :medium_dash_dotted, :thin_dash_dot_dotted,
39
+ # :medium_dash_dot_dotted, :slanted_medium_dash_dotted
40
+ # Default: :none
41
+ styles = [ :thin, :medium, :dashed, :dotted, :thick,
42
+ :double, :hair, :medium_dashed, :thin_dash_dotted,
43
+ :medium_dash_dotted, :thin_dash_dot_dotted,
44
+ :medium_dash_dot_dotted, :slanted_medium_dash_dotted ]
45
+ enum :left, :none, *styles
46
+ enum :right, :none, *styles
47
+ enum :top, :none, *styles
48
+ enum :bottom, :none, *styles
49
+
50
+ ##
51
+ # Color attributes
52
+ colors :bottom_color, :top_color, :left_color, :right_color,
53
+ :pattern_fg_color, :pattern_bg_color,
54
+ :diagonal_color
55
+ ##
56
+ # Text direction
57
+ # Valid values: :context, :left_to_right, :right_to_left
58
+ # Default: :context
59
+ enum :text_direction, :context, :left_to_right, :right_to_left,
60
+ :left_to_right => [:ltr, :l2r],
61
+ :right_to_left => [:rtl, :r2l]
62
+ alias :reading_order :text_direction
63
+ alias :reading_order= :text_direction=
64
+ ##
65
+ # Indentation level
66
+ enum :indent_level, 0, Integer
67
+ alias :indent :indent_level
68
+ alias :indent= :indent_level=
69
+ ##
70
+ # Horizontal alignment
71
+ # Valid values: :default, :left, :center, :right, :fill, :justify, :merge,
72
+ # :distributed
73
+ # Default: :default
74
+ enum :horizontal_align, :default, :left, :center, :right, :fill, :justify,
75
+ :merge, :distributed,
76
+ :center => :centre,
77
+ :merge => [ :center_across, :centre_across ],
78
+ :distributed => :equal_space
79
+ ##
80
+ # Vertical alignment
81
+ # Valid values: :bottom, :top, :middle, :justify, :distributed
82
+ # Default: :bottom
83
+ enum :vertical_align, :bottom, :top, :middle, :justify, :distributed,
84
+ :distributed => [:vdistributed, :vequal_space, :equal_space],
85
+ :justify => :vjustify,
86
+ :middle => [:vcenter, :vcentre, :center, :centre]
87
+ attr_accessor :font, :number_format, :name, :pattern, :used_merge
88
+ ##
89
+ # Text rotation
90
+ attr_reader :rotation
91
+ def initialize opts={}
92
+ @font = Font.new client("Arial", 'UTF-8'), :family => :swiss
93
+ @number_format = client 'GENERAL', 'UTF-8'
94
+ @rotation = 0
95
+ @pattern = 0
96
+ @bottom_color = :black
97
+ @top_color = :black
98
+ @left_color = :black
99
+ @right_color = :black
100
+ @diagonal_color = :black
101
+ @pattern_fg_color = :border
102
+ @pattern_bg_color = :pattern_bg
103
+ @regexes = {
104
+ :date => Regexp.new(client("[YMD]", 'UTF-8')),
105
+ :date_or_time => Regexp.new(client("[hmsYMD]", 'UTF-8')),
106
+ :datetime => Regexp.new(client("([YMD].*[HS])|([HS].*[YMD])", 'UTF-8')),
107
+ :time => Regexp.new(client("[hms]", 'UTF-8')),
108
+ :number => Regexp.new(client("[\#]", 'UTF-8'))
109
+ }
110
+
111
+ # Temp code to prevent merged formats in non-merged cells.
112
+ @used_merge = 0
113
+ update_format(opts)
114
+
115
+ yield self if block_given?
116
+ end
117
+
118
+ def update_format(opts = {})
119
+ opts.each do |attribute, value|
120
+ writer = "#{attribute}="
121
+ @font.respond_to?(writer) ? @font.send(writer,value) : self.send(writer, value)
122
+ end
123
+ self
124
+ end
125
+
126
+ ##
127
+ # Combined method for both horizontal and vertical alignment. Sets the
128
+ # first valid value (e.g. Format#align = :justify only sets the horizontal
129
+ # alignment. Use one of the aliases prefixed with :v if you need to
130
+ # disambiguate.)
131
+ #
132
+ # This is essentially a backward-compatibility method and may be removed at
133
+ # some point in the future.
134
+ def align= location
135
+ self.horizontal_align = location
136
+ rescue ArgumentError
137
+ self.vertical_align = location rescue ArgumentError
138
+ end
139
+ ##
140
+ # Returns an Array containing the line styles of the four borders:
141
+ # bottom, top, right, left
142
+ def border
143
+ [bottom, top, right, left]
144
+ end
145
+ ##
146
+ # Set same line style on all four borders at once (left, right, top, bottom)
147
+ def border=(style)
148
+ [:bottom=, :top=, :right=, :left=].each do |writer| send writer, style end
149
+ end
150
+ ##
151
+ # Returns an Array containing the colors of the four borders:
152
+ # bottom, top, right, left
153
+ def border_color
154
+ [@bottom_color,@top_color,@right_color,@left_color]
155
+ end
156
+ ##
157
+ # Set all four border colors to _color_ (left, right, top, bottom)
158
+ def border_color=(color)
159
+ [:bottom_color=, :top_color=, :right_color=, :left_color=].each do |writer|
160
+ send writer, color end
161
+ end
162
+ ##
163
+ # Set the Text rotation
164
+ # Valid values: Integers from -90 to 90,
165
+ # or :stacked (sets #rotation_stacked to true)
166
+ def rotation=(rot)
167
+ if rot.to_s.downcase == 'stacked'
168
+ @rotation_stacked = true
169
+ @rotation = 0
170
+ elsif rot.kind_of?(Integer)
171
+ @rotation_stacked = false
172
+ @rotation = rot % 360
173
+ else
174
+ raise TypeError, "rotation value must be an Integer or the String 'stacked'"
175
+ end
176
+ end
177
+ ##
178
+ # Backward compatibility method. May disappear at some point in the future.
179
+ def center_across!
180
+ self.horizontal_align = :merge
181
+ end
182
+ alias :merge! :center_across!
183
+ ##
184
+ # Is the cell formatted as a Date?
185
+ def date?
186
+ !number? && !!@regexes[:date].match(@number_format.to_s)
187
+ end
188
+ ##
189
+ # Is the cell formatted as a Date or Time?
190
+ def date_or_time?
191
+ !number? && !!@regexes[:date_or_time].match(@number_format.to_s)
192
+ end
193
+ ##
194
+ # Is the cell formatted as a DateTime?
195
+ def datetime?
196
+ !number? && !!@regexes[:datetime].match(@number_format.to_s)
197
+ end
198
+ ##
199
+ # Is the cell formatted as a Time?
200
+ def time?
201
+ !number? && !!@regexes[:time].match(@number_format.to_s)
202
+ end
203
+ ##
204
+ # Is the cell formatted as a number?
205
+ def number?
206
+ !!@regexes[:number].match(@number_format.to_s)
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,9 @@
1
+ module Spreadsheet
2
+ ##
3
+ # Formula implementation. At the moment this is just a placeholder.
4
+ # You may access the last calculated #value, other attributes are needed for
5
+ # writing the Formula back into modified Excel Files.
6
+ class Formula
7
+ attr_accessor :data, :value, :shared
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Spreadsheet
2
+ module Helpers
3
+ def rcompact(array)
4
+ while !array.empty? && array.last.nil?
5
+ array.pop
6
+ end
7
+ array
8
+ end
9
+ module_function :rcompact
10
+ end
11
+ end
@@ -0,0 +1,43 @@
1
+ require 'uri'
2
+ require 'spreadsheet/encodings'
3
+
4
+ module Spreadsheet
5
+ ##
6
+ # The Link class. Is a Subclass of String, which lets you treat a Cell that
7
+ # contains a Link just as if it was a String (containing the link's description
8
+ # if there is one or the url with fragment otherwise), but gives you access
9
+ # to the url, fragment and target_frame if you need it.
10
+ #
11
+ #
12
+ # Interesting Attributes
13
+ # #url :: The Uniform Resource Location this Link points to.
14
+ # #fragment :: Also called text mark: http://example.com/page.html#fragment
15
+ # #target_frame :: Which frame a Link should be opened in, should also support
16
+ # the special frames _blank, _parent, _self and _top.
17
+ # #dos :: Excel may store a DOS-Filename together with the long
18
+ # Filename introduced in VFAT. You probably will not need this,
19
+ # but if you do, here is where you can find it.
20
+ class Link < String
21
+ include Encodings
22
+ attr_accessor :target_frame, :url, :dos, :fragment
23
+ def initialize url='', description=url, fragment=nil
24
+ super description
25
+ @url = url
26
+ @fragment = fragment
27
+ end
28
+ ##
29
+ # The Url with the fragment appended if present.
30
+ def href
31
+ href = (@url || @dos).to_s.dup
32
+ if @fragment
33
+ href << client('#', 'UTF-8') << @fragment
34
+ end
35
+ href
36
+ end
37
+ ##
38
+ # Attempts to parse the output of href. May raise a URI::InvalidURIError
39
+ def to_uri
40
+ URI.parse href
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ require 'spreadsheet/encodings'
2
+
3
+ module Spreadsheet
4
+ ##
5
+ # The Note class is a Subclass of String and represents a comment/note/annotation
6
+ # someone made to a cell.
7
+ #
8
+ #
9
+ # Interesting Attributes
10
+ # #author :: The name of the author who wrote the note
11
+ class Note
12
+ include Encodings
13
+ attr_accessor :author, :length, :objID, :row, :col, :text
14
+ def initialize
15
+ @author = nil
16
+ @length = 0
17
+ @objID = nil
18
+ @row = -1
19
+ @col = -1
20
+ @text = ""
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require 'spreadsheet/encodings'
2
+
3
+ module Spreadsheet
4
+ ##
5
+ # The NoteObject class is made to handle the text output from the
6
+ # object, txo, continue records which contain a comment's text record.
7
+ #
8
+ #
9
+ class NoteObject
10
+ include Encodings
11
+ attr_accessor :objID, :text
12
+ def initialize
13
+ @objID = -1
14
+ @text = ""
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,151 @@
1
+ require 'spreadsheet/helpers'
2
+
3
+ module Spreadsheet
4
+ ##
5
+ # The Row class. Encapsulates Cell data and formatting.
6
+ # Since Row is a subclass of Array, you may use all the standard Array methods
7
+ # to manipulate a Row.
8
+ # By convention, Row#at will give you raw values, while Row#[] may be
9
+ # overridden to return enriched data if necessary (see also the Date- and
10
+ # DateTime-handling in Excel::Row#[]
11
+ #
12
+ # Useful Attributes are:
13
+ # #idx:: The 0-based index of this Row in its Worksheet.
14
+ # #formats:: A parallel array containing Formatting information for
15
+ # all cells stored in a Row.
16
+ # #default_format:: The default Format used when writing a Cell if no explicit
17
+ # Format is stored in #formats for the cell.
18
+ # #height:: The height of this Row in points (defaults to 12).
19
+ class Row < Array
20
+ include Datatypes
21
+ class << self
22
+ def format_updater *keys
23
+ keys.each do |key|
24
+ unless instance_methods.include? "unupdated_#{key}="
25
+ alias_method :"unupdated_#{key}=", :"#{key}="
26
+ define_method "#{key}=" do |value|
27
+ send "unupdated_#{key}=", value
28
+ @worksheet.row_updated @idx, self if @worksheet
29
+ value
30
+ end
31
+ end
32
+ end
33
+ end
34
+ def updater *keys
35
+ keys.each do |key|
36
+ ## Passing blocks to methods defined with define_method is not possible
37
+ # in Ruby 1.8:
38
+ # http://groups.google.com/group/ruby-talk-google/msg/778184912b769e5f
39
+ # use class_eval as suggested by someone else in
40
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=25732&group_id=678&atid=2677
41
+ class_eval <<-SRC, __FILE__, __LINE__
42
+ def #{key}(*args)
43
+ res = super(*args)
44
+ @worksheet.row_updated @idx, self if @worksheet
45
+ res
46
+ end
47
+ SRC
48
+ end
49
+ end
50
+ end
51
+ attr_reader :formats
52
+ attr_accessor :idx, :height, :worksheet
53
+ boolean :hidden, :collapsed
54
+ enum :outline_level, 0, Integer
55
+ updater :[]=, :clear, :concat, :delete, :delete_if, :fill, :insert, :map!,
56
+ :pop, :push, :reject!, :replace, :reverse!, :shift, :slice!,
57
+ :sort!, :uniq!, :unshift
58
+ format_updater :collapsed, :height, :hidden, :outline_level
59
+ def initialize worksheet, idx, cells=[]
60
+ @default_format = nil
61
+ @worksheet = worksheet
62
+ @idx = idx
63
+ super cells
64
+ @formats = []
65
+ @height = 12.1
66
+ end
67
+ ##
68
+ # The default Format of this Row, if you have set one.
69
+ # Returns the Worksheet's default or the Workbook's default Format otherwise.
70
+ def default_format
71
+ @default_format || @worksheet.default_format || @workbook.default_format
72
+ end
73
+ ##
74
+ # Set the default Format used when writing a Cell if no explicit Format is
75
+ # stored for the cell.
76
+ def default_format= format
77
+ @worksheet.add_format format if @worksheet
78
+ @default_format = format
79
+ end
80
+ format_updater :default_format
81
+ ##
82
+ # #first_used the 0-based index of the first non-blank Cell.
83
+ def first_used
84
+ [ index_of_first(self), index_of_first(@formats) ].compact.min
85
+ end
86
+ ##
87
+ # The Format for the Cell at _idx_ (0-based), or the first valid Format in
88
+ # Row#default_format, Column#default_format and Worksheet#default_format.
89
+ def format idx
90
+ @formats[idx] || @default_format \
91
+ || @worksheet.column(idx).default_format if @worksheet
92
+ end
93
+ ##
94
+ # Returns a copy of self with nil-values appended for empty cells that have
95
+ # an associated Format.
96
+ # This is primarily a helper-function for the writer classes.
97
+ def formatted
98
+ copy = dup
99
+ Helpers.rcompact(@formats)
100
+ if copy.length < @formats.size
101
+ copy.concat Array.new(@formats.size - copy.length)
102
+ end
103
+ copy
104
+ end
105
+ ##
106
+ # Same as Row#size, but takes into account formatted empty cells
107
+ def formatted_size
108
+ Helpers.rcompact(@formats)
109
+ sz = size
110
+ fs = @formats.size
111
+ fs > sz ? fs : sz
112
+ end
113
+ ##
114
+ # #first_unused (really last used + 1) - the 0-based index of the first of
115
+ # all remaining contiguous blank Cells.
116
+ alias :first_unused :formatted_size
117
+ def inspect
118
+ variables = instance_variables.collect do |name|
119
+ "%s=%s" % [name, instance_variable_get(name)]
120
+ end.join(' ')
121
+ sprintf "#<%s:0x%014x %s %s>", self.class, object_id, variables, super
122
+ end
123
+ ##
124
+ # Set the Format for the Cell at _idx_ (0-based).
125
+ def set_format idx, fmt
126
+ @formats[idx] = fmt
127
+ @worksheet.add_format fmt
128
+ @worksheet.row_updated @idx, self if @worksheet
129
+ fmt
130
+ end
131
+
132
+ def update_format(idx, opts = {})
133
+ if @formats[idx]
134
+ @formats[idx].update_format(opts)
135
+ else
136
+ fmt = default_format.clone
137
+ fmt.font = fmt.font.clone
138
+ @formats[idx] = fmt.update_format(opts)
139
+ end
140
+ @worksheet.add_format @formats[idx]
141
+ @worksheet.row_updated @idx, self if @worksheet
142
+ end
143
+
144
+ private
145
+ def index_of_first ary # :nodoc:
146
+ if first = ary.find do |elm| !elm.nil? end
147
+ ary.index first
148
+ end
149
+ end
150
+ end
151
+ end