ttb-spreadsheet 0.6.5.8

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 (65) hide show
  1. data/GUIDE.txt +267 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +18 -0
  4. data/History.txt +365 -0
  5. data/LICENSE.txt +619 -0
  6. data/Manifest.txt +62 -0
  7. data/README.txt +107 -0
  8. data/Rakefile +0 -0
  9. data/bin/xlsopcodes +18 -0
  10. data/lib/parseexcel.rb +27 -0
  11. data/lib/parseexcel/parseexcel.rb +75 -0
  12. data/lib/parseexcel/parser.rb +11 -0
  13. data/lib/spreadsheet.rb +79 -0
  14. data/lib/spreadsheet/column.rb +71 -0
  15. data/lib/spreadsheet/compatibility.rb +23 -0
  16. data/lib/spreadsheet/datatypes.rb +106 -0
  17. data/lib/spreadsheet/encodings.rb +57 -0
  18. data/lib/spreadsheet/excel.rb +88 -0
  19. data/lib/spreadsheet/excel/error.rb +26 -0
  20. data/lib/spreadsheet/excel/internals.rb +365 -0
  21. data/lib/spreadsheet/excel/internals/biff5.rb +17 -0
  22. data/lib/spreadsheet/excel/internals/biff8.rb +19 -0
  23. data/lib/spreadsheet/excel/offset.rb +41 -0
  24. data/lib/spreadsheet/excel/reader.rb +1173 -0
  25. data/lib/spreadsheet/excel/reader/biff5.rb +22 -0
  26. data/lib/spreadsheet/excel/reader/biff8.rb +199 -0
  27. data/lib/spreadsheet/excel/row.rb +92 -0
  28. data/lib/spreadsheet/excel/sst_entry.rb +46 -0
  29. data/lib/spreadsheet/excel/workbook.rb +80 -0
  30. data/lib/spreadsheet/excel/worksheet.rb +100 -0
  31. data/lib/spreadsheet/excel/writer.rb +1 -0
  32. data/lib/spreadsheet/excel/writer/biff8.rb +75 -0
  33. data/lib/spreadsheet/excel/writer/format.rb +253 -0
  34. data/lib/spreadsheet/excel/writer/workbook.rb +690 -0
  35. data/lib/spreadsheet/excel/writer/worksheet.rb +891 -0
  36. data/lib/spreadsheet/font.rb +92 -0
  37. data/lib/spreadsheet/format.rb +177 -0
  38. data/lib/spreadsheet/formula.rb +9 -0
  39. data/lib/spreadsheet/helpers.rb +11 -0
  40. data/lib/spreadsheet/link.rb +43 -0
  41. data/lib/spreadsheet/row.rb +132 -0
  42. data/lib/spreadsheet/workbook.rb +126 -0
  43. data/lib/spreadsheet/worksheet.rb +287 -0
  44. data/lib/spreadsheet/writer.rb +30 -0
  45. data/spreadsheet.gemspec +20 -0
  46. data/test/data/test_changes.xls +0 -0
  47. data/test/data/test_copy.xls +0 -0
  48. data/test/data/test_datetime.xls +0 -0
  49. data/test/data/test_empty.xls +0 -0
  50. data/test/data/test_formula.xls +0 -0
  51. data/test/data/test_long_sst_record.xls +0 -0
  52. data/test/data/test_missing_row.xls +0 -0
  53. data/test/data/test_version_excel5.xls +0 -0
  54. data/test/data/test_version_excel95.xls +0 -0
  55. data/test/data/test_version_excel97.xls +0 -0
  56. data/test/excel/row.rb +35 -0
  57. data/test/excel/writer/workbook.rb +23 -0
  58. data/test/excel/writer/worksheet.rb +24 -0
  59. data/test/font.rb +163 -0
  60. data/test/integration.rb +1311 -0
  61. data/test/row.rb +33 -0
  62. data/test/suite.rb +17 -0
  63. data/test/workbook.rb +29 -0
  64. data/test/worksheet.rb +80 -0
  65. metadata +151 -0
@@ -0,0 +1,92 @@
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
+ opts.each do |key, val|
68
+ self.send "#{key}=", val
69
+ end
70
+ end
71
+ ##
72
+ # Sets #weight to :bold if(_bool_), :normal otherwise.
73
+ def bold= bool
74
+ self.weight = bool ? :bold : nil
75
+ end
76
+ def key # :nodoc:
77
+ key = @name.dup
78
+ underscore = client('_', 'UTF-8')
79
+ key << underscore << client(size.to_s, 'US-ASCII')
80
+ key << client('_', 'UTF-8') << client(weight.to_s, 'US-ASCII')
81
+ key << client('_italic', 'UTF-8') if italic?
82
+ key << client('_strikeout', 'UTF-8') if strikeout?
83
+ key << client('_outline', 'UTF-8') if outline?
84
+ key << client('_shadow', 'UTF-8') if shadow?
85
+ key << underscore << client(escapement.to_s, 'US-ASCII')
86
+ key << underscore << client(underline.to_s, 'US-ASCII')
87
+ key << underscore << client(color.to_s, 'US-ASCII')
88
+ key << underscore << client(family.to_s, 'US-ASCII')
89
+ key << underscore << client(encoding.to_s, 'US-ASCII')
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,177 @@
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:: Draw a border to the left of the cell.
25
+ # #right:: Draw a border to the right of the cell.
26
+ # #top:: Draw a border at the top of the cell.
27
+ # #bottom:: Draw a border 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, :left, :right,
33
+ :top, :bottom, :rotation_stacked
34
+ ##
35
+ # Color attributes
36
+ colors :bottom_color, :top_color, :left_color, :right_color,
37
+ :pattern_fg_color, :pattern_bg_color,
38
+ :diagonal_color
39
+ ##
40
+ # Text direction
41
+ # Valid values: :context, :left_to_right, :right_to_left
42
+ # Default: :context
43
+ enum :text_direction, :context, :left_to_right, :right_to_left,
44
+ :left_to_right => [:ltr, :l2r],
45
+ :right_to_left => [:rtl, :r2l]
46
+ alias :reading_order :text_direction
47
+ alias :reading_order= :text_direction=
48
+ ##
49
+ # Indentation level
50
+ enum :indent_level, 0, Integer
51
+ alias :indent :indent_level
52
+ alias :indent= :indent_level=
53
+ ##
54
+ # Horizontal alignment
55
+ # Valid values: :default, :left, :center, :right, :fill, :justify, :merge,
56
+ # :distributed
57
+ # Default: :default
58
+ enum :horizontal_align, :default, :left, :center, :right, :fill, :justify,
59
+ :merge, :distributed,
60
+ :center => :centre,
61
+ :merge => [ :center_across, :centre_across ],
62
+ :distributed => :equal_space
63
+ ##
64
+ # Vertical alignment
65
+ # Valid values: :bottom, :top, :middle, :justify, :distributed
66
+ # Default: :bottom
67
+ enum :vertical_align, :bottom, :top, :middle, :justify, :distributed,
68
+ :distributed => [:vdistributed, :vequal_space, :equal_space],
69
+ :justify => :vjustify,
70
+ :middle => [:vcenter, :vcentre, :center, :centre]
71
+ attr_accessor :font, :number_format, :name, :pattern, :used_merge
72
+ ##
73
+ # Text rotation
74
+ attr_reader :rotation
75
+ def initialize opts={}
76
+ @font = Font.new client("Arial", 'UTF-8'), :family => :swiss
77
+ @number_format = client 'GENERAL', 'UTF-8'
78
+ @rotation = 0
79
+ @pattern = 0
80
+ @bottom_color = :builtin_black
81
+ @top_color = :builtin_black
82
+ @left_color = :builtin_black
83
+ @right_color = :builtin_black
84
+ @diagonal_color = :builtin_black
85
+ @pattern_fg_color = :border
86
+ @pattern_bg_color = :pattern_bg
87
+ # Temp code to prevent merged formats in non-merged cells.
88
+ @used_merge = 0
89
+ opts.each do |key, val|
90
+ writer = "#{key}="
91
+ if @font.respond_to? writer
92
+ @font.send writer, val
93
+ else
94
+ self.send writer, val
95
+ end
96
+ end
97
+ yield self if block_given?
98
+ end
99
+ ##
100
+ # Combined method for both horizontal and vertical alignment. Sets the
101
+ # first valid value (e.g. Format#align = :justify only sets the horizontal
102
+ # alignment. Use one of the aliases prefixed with :v if you need to
103
+ # disambiguate.)
104
+ #
105
+ # This is essentially a backward-compatibility method and may be removed at
106
+ # some point in the future.
107
+ def align= location
108
+ self.horizontal_align = location
109
+ rescue ArgumentError
110
+ self.vertical_align = location rescue ArgumentError
111
+ end
112
+ ##
113
+ # Returns an Array containing the status of the four borders:
114
+ # bottom, top, right, left
115
+ def border
116
+ [bottom,top,right,left]
117
+ end
118
+ ##
119
+ # Activate or deactivate all four borders (left, right, top, bottom)
120
+ def border=(boolean)
121
+ [:bottom=, :top=, :right=, :left=].each do |writer| send writer, boolean end
122
+ end
123
+ ##
124
+ # Returns an Array containing the colors of the four borders:
125
+ # bottom, top, right, left
126
+ def border_color
127
+ [@bottom_color,@top_color,@left_color,@right_color]
128
+ end
129
+ ##
130
+ # Set all four border colors to _color_ (left, right, top, bottom)
131
+ def border_color=(color)
132
+ [:bottom_color=, :top_color=, :right_color=, :left_color=].each do |writer|
133
+ send writer, color end
134
+ end
135
+ ##
136
+ # Set the Text rotation
137
+ # Valid values: Integers from -90 to 90,
138
+ # or :stacked (sets #rotation_stacked to true)
139
+ def rotation=(rot)
140
+ if rot.to_s.downcase == 'stacked'
141
+ @rotation_stacked = true
142
+ @rotation = 0
143
+ elsif rot.kind_of?(Integer)
144
+ @rotation_stacked = false
145
+ @rotation = rot % 360
146
+ else
147
+ raise TypeError, "rotation value must be an Integer or the String 'stacked'"
148
+ end
149
+ end
150
+ ##
151
+ # Backward compatibility method. May disappear at some point in the future.
152
+ def center_across!
153
+ self.horizontal_align = :merge
154
+ end
155
+ alias :merge! :center_across!
156
+ ##
157
+ # Is the cell formatted as a Date?
158
+ def date?
159
+ !!Regexp.new(client("[YMD]", 'UTF-8')).match(@number_format.to_s)
160
+ end
161
+ ##
162
+ # Is the cell formatted as a Date or Time?
163
+ def date_or_time?
164
+ !!Regexp.new(client("[hmsYMD]", 'UTF-8')).match(@number_format.to_s)
165
+ end
166
+ ##
167
+ # Is the cell formatted as a DateTime?
168
+ def datetime?
169
+ !!Regexp.new(client("([YMD].*[HS])|([HS].*[YMD])", 'UTF-8')).match(@number_format.to_s)
170
+ end
171
+ ##
172
+ # Is the cell formatted as a Time?
173
+ def time?
174
+ !!Regexp.new(client("[hms]", 'UTF-8')).match(@number_format.to_s)
175
+ end
176
+ end
177
+ 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
+ class Array
2
+ def rcompact
3
+ dup.rcompact!
4
+ end
5
+ def rcompact!
6
+ while !empty? && last.nil?
7
+ pop
8
+ end
9
+ self
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,132 @@
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, :default_format
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
+ # Set the default Format used when writing a Cell if no explicit Format is
69
+ # stored for the cell.
70
+ def default_format= format
71
+ @worksheet.add_format format if @worksheet
72
+ @default_format = format
73
+ end
74
+ format_updater :default_format
75
+ ##
76
+ # #first_used the 0-based index of the first non-blank Cell.
77
+ def first_used
78
+ [ index_of_first(self), index_of_first(@formats) ].compact.min
79
+ end
80
+ ##
81
+ # The Format for the Cell at _idx_ (0-based), or the first valid Format in
82
+ # Row#default_format, Column#default_format and Worksheet#default_format.
83
+ def format idx
84
+ @formats[idx] || @default_format \
85
+ || @worksheet.column(idx).default_format if @worksheet
86
+ end
87
+ ##
88
+ # Returns a copy of self with nil-values appended for empty cells that have
89
+ # an associated Format.
90
+ # This is primarily a helper-function for the writer classes.
91
+ def formatted
92
+ copy = dup
93
+ @formats.rcompact!
94
+ if copy.length < @formats.size
95
+ copy.concat Array.new(@formats.size - copy.length)
96
+ end
97
+ copy
98
+ end
99
+ ##
100
+ # Same as Row#size, but takes into account formatted empty cells
101
+ def formatted_size
102
+ @formats.rcompact!
103
+ sz = size
104
+ fs = @formats.size
105
+ fs > sz ? fs : sz
106
+ end
107
+ ##
108
+ # #first_unused (really last used + 1) - the 0-based index of the first of
109
+ # all remaining contiguous blank Cells.
110
+ alias :first_unused :formatted_size
111
+ def inspect
112
+ variables = instance_variables.collect do |name|
113
+ "%s=%s" % [name, instance_variable_get(name)]
114
+ end.join(' ')
115
+ sprintf "#<%s:0x%014x %s %s>", self.class, object_id, variables, super
116
+ end
117
+ ##
118
+ # Set the Format for the Cell at _idx_ (0-based).
119
+ def set_format idx, fmt
120
+ @formats[idx] = fmt
121
+ @worksheet.add_format fmt
122
+ @worksheet.row_updated @idx, self if @worksheet
123
+ fmt
124
+ end
125
+ private
126
+ def index_of_first ary # :nodoc:
127
+ if first = ary.find do |elm| !elm.nil? end
128
+ ary.index first
129
+ end
130
+ end
131
+ end
132
+ end