spreadsheet 0.6.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 (47) hide show
  1. data/GUIDE.txt +209 -0
  2. data/History.txt +8 -0
  3. data/LICENSE.txt +619 -0
  4. data/Manifest.txt +46 -0
  5. data/README.txt +54 -0
  6. data/Rakefile +15 -0
  7. data/lib/parseexcel.rb +27 -0
  8. data/lib/parseexcel/parseexcel.rb +75 -0
  9. data/lib/parseexcel/parser.rb +11 -0
  10. data/lib/spreadsheet.rb +79 -0
  11. data/lib/spreadsheet/datatypes.rb +99 -0
  12. data/lib/spreadsheet/encodings.rb +49 -0
  13. data/lib/spreadsheet/excel.rb +75 -0
  14. data/lib/spreadsheet/excel/error.rb +26 -0
  15. data/lib/spreadsheet/excel/internals.rb +322 -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 +37 -0
  19. data/lib/spreadsheet/excel/reader.rb +798 -0
  20. data/lib/spreadsheet/excel/reader/biff5.rb +22 -0
  21. data/lib/spreadsheet/excel/reader/biff8.rb +168 -0
  22. data/lib/spreadsheet/excel/row.rb +67 -0
  23. data/lib/spreadsheet/excel/sst_entry.rb +45 -0
  24. data/lib/spreadsheet/excel/workbook.rb +76 -0
  25. data/lib/spreadsheet/excel/worksheet.rb +85 -0
  26. data/lib/spreadsheet/excel/writer.rb +1 -0
  27. data/lib/spreadsheet/excel/writer/biff8.rb +66 -0
  28. data/lib/spreadsheet/excel/writer/format.rb +270 -0
  29. data/lib/spreadsheet/excel/writer/workbook.rb +586 -0
  30. data/lib/spreadsheet/excel/writer/worksheet.rb +556 -0
  31. data/lib/spreadsheet/font.rb +86 -0
  32. data/lib/spreadsheet/format.rb +172 -0
  33. data/lib/spreadsheet/formula.rb +9 -0
  34. data/lib/spreadsheet/row.rb +87 -0
  35. data/lib/spreadsheet/workbook.rb +120 -0
  36. data/lib/spreadsheet/worksheet.rb +215 -0
  37. data/lib/spreadsheet/writer.rb +29 -0
  38. data/test/data/test_copy.xls +0 -0
  39. data/test/data/test_version_excel5.xls +0 -0
  40. data/test/data/test_version_excel95.xls +0 -0
  41. data/test/data/test_version_excel97.xls +0 -0
  42. data/test/excel/row.rb +29 -0
  43. data/test/font.rb +163 -0
  44. data/test/integration.rb +1021 -0
  45. data/test/workbook.rb +21 -0
  46. data/test/worksheet.rb +62 -0
  47. metadata +113 -0
@@ -0,0 +1,86 @@
1
+ require 'spreadsheet/datatypes'
2
+ require 'spreadsheet/encodings'
3
+
4
+ module Spreadsheet
5
+ ##
6
+ # Font formatting data
7
+ class Font
8
+ include Datatypes
9
+ include Encodings
10
+ attr_accessor :name
11
+ ##
12
+ # You can set the following boolean Font attributes
13
+ # * #italic
14
+ # * #strikeout
15
+ # * #outline
16
+ # * #shadow
17
+ boolean :italic, :strikeout, :outline, :shadow
18
+ ##
19
+ # Font color
20
+ colors :color
21
+ ##
22
+ # Font weight
23
+ # Valid values: :normal, :bold or any positive Integer.
24
+ # In Excel:
25
+ # 100 <= weight <= 1000
26
+ # :bold => 700
27
+ # :normal => 400
28
+ # Default: :normal
29
+ enum :weight, :normal, :bold, Integer, :bold => :b
30
+ ##
31
+ # Escapement
32
+ # Valid values: :normal, :superscript or :subscript.
33
+ # Default: :normal
34
+ enum :escapement, :normal, :superscript, :subscript,
35
+ :subscript => :sub,
36
+ :superscript => :super
37
+ # Font size
38
+ # Valid values: Any positive Integer.
39
+ # Default: 10
40
+ enum :size, 10, Numeric
41
+ # Underline type
42
+ # Valid values: :none, :single, :double, :single_accounting and
43
+ # :double_accounting.
44
+ # Default: :none
45
+ enum :underline, :none, :single, :double,
46
+ :single_accounting, :double_accounting,
47
+ :single => true
48
+ # Font Family
49
+ # Valid values: :none, :roman, :swiss, :modern, :script, :decorative
50
+ # Default: :none
51
+ enum :family, :none, :roman, :swiss, :modern, :script, :decorative
52
+ # Font Family
53
+ # Valid values: :default, :iso_latin1, :symbol, :apple_roman, :shift_jis,
54
+ # :korean_hangul, :korean_johab, :chinese_simplified,
55
+ # :chinese_traditional, :greek, :turkish, :vietnamese,
56
+ # :hebrew, :arabic, :cyrillic, :thai, :iso_latin2, :oem_latin1
57
+ # Default: :default
58
+ enum :encoding, :default, :iso_latin1, :symbol, :apple_roman, :shift_jis,
59
+ :korean_hangul, :korean_johab, :chinese_simplified,
60
+ :chinese_traditional, :greek, :turkish, :vietnamese,
61
+ :hebrew, :arabic, :cyrillic, :thai, :iso_latin2, :oem_latin1
62
+ def initialize name
63
+ self.name = name
64
+ @color = :text
65
+ end
66
+ ##
67
+ # Sets #weight to :bold if(_bool_), :normal otherwise.
68
+ def bold= bool
69
+ self.weight = bool ? :bold : nil
70
+ end
71
+ def key # :nodoc:
72
+ key = @name.dup
73
+ key << '_' << size.to_s
74
+ key << '_' << weight.to_s
75
+ key << '_italic' if italic?
76
+ key << '_strikeout' if strikeout?
77
+ key << '_outline' if outline?
78
+ key << '_shadow' if shadow?
79
+ key << '_' << escapement.to_s
80
+ key << '_' << underline.to_s
81
+ key << '_' << color.to_s
82
+ key << '_' << family.to_s
83
+ key << '_' << encoding.to_s
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,172 @@
1
+ require 'spreadsheet/datatypes'
2
+ require 'spreadsheet/encodings'
3
+ require 'spreadsheet/font'
4
+
5
+ module Spreadsheet
6
+ ##
7
+ # Formatting data
8
+ class Format
9
+ include Encodings
10
+ include Datatypes
11
+ ##
12
+ # You can set the following boolean attributes:
13
+ # #cross_down:: Draws a Line from the top-left to the bottom-right
14
+ # corner of a cell.
15
+ # #cross_up:: Draws a Line from the bottom-left to the top-right
16
+ # corner of a cell.
17
+ # #hidden:: The cell is hidden.
18
+ # #locked:: The cell is locked.
19
+ # #merge_range:: The cell is in a merged range.
20
+ # #shrink:: Shrink the contents to fit the cell.
21
+ # #text_justlast:: Force the last line of a cell to be justified. This
22
+ # probably makes sense if horizontal_align = :justify
23
+ # #left:: Draw a border to the left of the cell.
24
+ # #right:: Draw a border to the right of the cell.
25
+ # #top:: Draw a border at the top of the cell.
26
+ # #bottom:: Draw a border at the bottom of the cell.
27
+ # #rotation_stacked:: Characters in the cell are stacked on top of each
28
+ # other. Excel will ignore other rotation values if
29
+ # this is set.
30
+ boolean :cross_down, :cross_up, :hidden, :locked,
31
+ :merge_range, :shrink, :text_justlast, :text_wrap, :left, :right,
32
+ :top, :bottom, :rotation_stacked
33
+ ##
34
+ # Color attributes
35
+ colors :bottom_color, :top_color, :left_color, :right_color,
36
+ :bg_color, :pattern_fg_color, :pattern_bg_color,
37
+ :diagonal_color
38
+ ##
39
+ # Text direction
40
+ # Valid values: :context, :left_to_right, :right_to_left
41
+ # Default: :context
42
+ enum :text_direction, :context, :left_to_right, :right_to_left,
43
+ :left_to_right => [:ltr, :l2r],
44
+ :right_to_left => [:rtl, :r2l]
45
+ alias :reading_order :text_direction
46
+ alias :reading_order= :text_direction=
47
+ ##
48
+ # Indentation level
49
+ enum :indent_level, 0, Integer
50
+ alias :indent :indent_level
51
+ alias :indent= :indent_level=
52
+ ##
53
+ # Horizontal alignment
54
+ # Valid values: :default, :left, :center, :right, :fill, :justify, :merge,
55
+ # :distributed
56
+ # Default: :default
57
+ enum :horizontal_align, :default, :left, :center, :right, :fill, :justify,
58
+ :merge, :distributed,
59
+ :center => :centre,
60
+ :merge => [ :center_across, :centre_across ],
61
+ :distributed => :equal_space
62
+ ##
63
+ # Vertical alignment
64
+ # Valid values: :bottom, :top, :middle, :justify, :distributed
65
+ # Default: :bottom
66
+ enum :vertical_align, :bottom, :top, :middle, :justify, :distributed,
67
+ :distributed => [:vdistributed, :vequal_space, :equal_space],
68
+ :justify => :vjustify,
69
+ :middle => [:vcenter, :vcentre, :center, :centre]
70
+ attr_accessor :font, :number_format, :name, :pattern, :used_merge
71
+ ##
72
+ # Text rotation
73
+ attr_reader :rotation
74
+ def initialize opts={}
75
+ @font = Font.new client("Arial", 'UTF8')
76
+ @number_format = client 'General', 'UTF8'
77
+ @rotation = 0
78
+ @bg_color = :pattern_bg
79
+ @pattern = 0
80
+ @bottom_color = :border
81
+ @top_color = :border
82
+ @left_color = :border
83
+ @right_color = :border
84
+ @diagonal_color = :border
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
+ !!/[YMD]/.match(@number_format.to_s)
160
+ end
161
+ ##
162
+ # Is the cell formatted as a DateTime?
163
+ def datetime?
164
+ !!/([YMD].*[hms])|([hms].*[YMD])/.match(@number_format.to_s)
165
+ end
166
+ ##
167
+ # Is the cell formatted as a Time?
168
+ def time?
169
+ !!/[hms]/.match(@number_format.to_s)
170
+ end
171
+ end
172
+ 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,87 @@
1
+ module Spreadsheet
2
+ ##
3
+ # The Row class. Encapsulates Cell data and formatting.
4
+ # Since Row is a subclass of Array, you may use all the standard Array methods
5
+ # to manipulate a Row.
6
+ # By convention, Row#at will give you raw values, while Row#[] may be
7
+ # overridden to return enriched data if necessary (see also the Date- and
8
+ # DateTime-handling in Excel::Row#[]
9
+ #
10
+ # Useful Attributes are:
11
+ # #idx:: The 0-based index of this Row in its Worksheet.
12
+ # #formats:: A parallel array containing Formatting information for
13
+ # all cells stored in a Row.
14
+ # #default_format:: The default Format used when writing a Cell if no explicit
15
+ # Format is stored in #formats for the cell.
16
+ # #height:: The height of this Row in points (defaults to 12).
17
+ class Row < Array
18
+ class << self
19
+ def updater *keys
20
+ keys.each do |key|
21
+ define_method key do |*args|
22
+ res = super
23
+ @worksheet.row_updated @idx, self if @worksheet
24
+ res
25
+ end
26
+ end
27
+ end
28
+ end
29
+ attr_reader :formats, :default_format
30
+ attr_accessor :idx, :height, :worksheet
31
+ updater :[]=, :clear, :concat, :delete, :delete_if, :fill, :insert, :map!,
32
+ :pop, :push, :reject!, :replace, :reverse!, :shift, :slice!,
33
+ :sort!, :uniq!, :unshift
34
+ def initialize worksheet, idx, cells=[]
35
+ @worksheet = worksheet
36
+ @idx = idx
37
+ while !cells.empty? && !cells.last
38
+ cells.pop
39
+ end
40
+ super cells
41
+ @first_used ||= index_of_first self
42
+ @first_unused ||= size
43
+ @formats = []
44
+ @height = 12
45
+ end
46
+ ##
47
+ # Set the default Format used when writing a Cell if no explicit Format is
48
+ # stored for the cell.
49
+ def default_format= format
50
+ @worksheet.add_format format
51
+ @default_format = format
52
+ end
53
+ ##
54
+ # #first_unused (really last used + 1) - the 0-based index of the first of
55
+ # all remaining contiguous blank Cells.
56
+ alias :first_unused :size
57
+ ##
58
+ # #first_used the 0-based index of the first non-blank Cell.
59
+ def first_used
60
+ index_of_first self
61
+ end
62
+ ##
63
+ # The Format for the Cell at _idx_ (0-based), or default_format
64
+ # if no Format is set.
65
+ def format idx
66
+ @formats[idx] || @default_format
67
+ end
68
+ ##
69
+ # Set the Format for the Cell at _idx_ (0-based).
70
+ def set_format idx, fmt
71
+ @formats[idx] = fmt
72
+ @worksheet.add_format fmt
73
+ @worksheet.row_updated @idx, self if @worksheet
74
+ fmt
75
+ end
76
+ def inspect
77
+ variables = instance_variables.collect do |name|
78
+ "%s=%s" % [name, instance_variable_get(name)]
79
+ end.join(' ')
80
+ sprintf "#<%s:0x%014x %s %s>", self.class, object_id, variables, super
81
+ end
82
+ private
83
+ def index_of_first ary # :nodoc:
84
+ ary.index(ary.find do |elm| elm end)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,120 @@
1
+ require 'spreadsheet/format'
2
+ require 'spreadsheet/encodings'
3
+
4
+ module Spreadsheet
5
+ ##
6
+ # The Workbook class represents a Spreadsheet-Document and is the entry point
7
+ # for all Spreadsheet manipulation.
8
+ #
9
+ # Interesting Attributes:
10
+ # #default_format:: The default format used for all cells in this Workbook.
11
+ # that have no format set explicitly or in
12
+ # Row#default_format or Worksheet#default_format.
13
+ class Workbook
14
+ include Encodings
15
+ attr_reader :io, :worksheets, :formats, :fonts
16
+ attr_accessor :encoding, :version, :default_format
17
+ def initialize io = nil, opts={:default_format => Format.new}
18
+ @worksheets = []
19
+ @io = io
20
+ @fonts = []
21
+ @formats = []
22
+ if @default_format = opts[:default_format]
23
+ @formats.push @default_format
24
+ end
25
+ end
26
+ ##
27
+ # Add a Font to the Workbook. Used by the parser. You should not need to
28
+ # use this Method.
29
+ def add_font font
30
+ @fonts.push font
31
+ end
32
+ ##
33
+ # Add a Format to the Workbook. If you use Row#set_format, you should not
34
+ # need to use this Method.
35
+ def add_format format
36
+ @formats.push(format).uniq!
37
+ format
38
+ end
39
+ ##
40
+ # Add a Worksheet to the Workbook.
41
+ def add_worksheet worksheet
42
+ worksheet.workbook = self
43
+ @worksheets.push worksheet
44
+ worksheet
45
+ end
46
+ ##
47
+ # Create a new Worksheet in this Workbook.
48
+ # Used without options this creates a Worksheet with the name 'WorksheetN'
49
+ # where the new Worksheet is the Nth Worksheet in this Workbook.
50
+ #
51
+ # Use the option <em>:name => 'My pretty Name'</em> to override this
52
+ # behavior.
53
+ def create_worksheet opts = {}
54
+ opts[:name] ||= client("Worksheet#{@worksheets.size.next}", 'UTF8')
55
+ add_worksheet Worksheet.new(opts)
56
+ end
57
+ ##
58
+ # The Font at _idx_
59
+ def font idx
60
+ @fonts[idx]
61
+ end
62
+ ##
63
+ # The Format at _idx_, or - if _idx_ is a String -
64
+ # the Format with name == _idx_
65
+ def format idx
66
+ case idx
67
+ when Integer
68
+ @formats[idx] || @default_format
69
+ when String
70
+ @formats.find do |fmt| fmt.name == idx end
71
+ end
72
+ end
73
+ def inspect
74
+ "#<#{self.class}:#{object_id} "
75
+ variables = (instance_variables - uninspect_variables).collect do |name|
76
+ "%s=%s" % [name, instance_variable_get(name)]
77
+ end.join(' ')
78
+ uninspect = uninspect_variables.collect do |name|
79
+ var = instance_variable_get name
80
+ "%s=%s[%i]" % [name, var.class, var.size]
81
+ end.join(' ')
82
+ sprintf "#<%s:0x%014x %s %s>", self.class, object_id,
83
+ variables, uninspect
84
+ end
85
+ def uninspect_variables # :nodoc:
86
+ %w{@formats @fonts @worksheets}
87
+ end
88
+ ##
89
+ # The Worksheet at _idx_, or - if _idx_ is a String -
90
+ # the Worksheet with name == _idx_
91
+ def worksheet idx
92
+ case idx
93
+ when Integer
94
+ @worksheets[idx]
95
+ when String
96
+ @worksheets.find do |sheet| sheet.name == idx end
97
+ end
98
+ end
99
+ ##
100
+ # Write this Workbook to a File, IO Stream or Writer Object. The latter will
101
+ # make more sense once there are more than just an Excel-Writer available.
102
+ def write io_path_or_writer
103
+ if io_path_or_writer.is_a? Writer
104
+ io_path_or_writer.write self
105
+ else
106
+ writer(io_path_or_writer).write(self)
107
+ end
108
+ end
109
+ ##
110
+ # Returns a new instance of the default Writer class for this Workbook (can
111
+ # only be an Excel::Writer::Workbook at this time)
112
+ def writer io_or_path, type=Excel, version=self.version
113
+ if type == Excel
114
+ Excel::Writer::Workbook.new io_or_path
115
+ else
116
+ raise NotImplementedError, "No Writer defined for #{type}"
117
+ end
118
+ end
119
+ end
120
+ end