rubyXL 1.2.10 → 2.1.1

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 (101) hide show
  1. data/Gemfile +14 -10
  2. data/Gemfile.lock +80 -21
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +88 -82
  5. data/Rakefile +7 -2
  6. data/VERSION +1 -1
  7. data/lib/rubyXL.rb +13 -7
  8. data/lib/rubyXL/cell.rb +108 -268
  9. data/lib/rubyXL/generic_storage.rb +40 -0
  10. data/lib/rubyXL/objects/border.rb +66 -0
  11. data/lib/rubyXL/objects/calculation_chain.rb +28 -0
  12. data/lib/rubyXL/objects/cell_style.rb +75 -0
  13. data/lib/rubyXL/objects/color.rb +25 -0
  14. data/lib/rubyXL/objects/column_range.rb +74 -0
  15. data/lib/rubyXL/objects/container_nodes.rb +122 -0
  16. data/lib/rubyXL/objects/data_validation.rb +43 -0
  17. data/lib/rubyXL/objects/document_properties.rb +76 -0
  18. data/lib/rubyXL/objects/extensions.rb +36 -0
  19. data/lib/rubyXL/objects/fill.rb +57 -0
  20. data/lib/rubyXL/objects/font.rb +111 -0
  21. data/lib/rubyXL/objects/formula.rb +24 -0
  22. data/lib/rubyXL/objects/ooxml_object.rb +295 -0
  23. data/lib/rubyXL/objects/reference.rb +110 -0
  24. data/lib/rubyXL/objects/relationships.rb +59 -0
  25. data/lib/rubyXL/objects/shared_strings.rb +57 -0
  26. data/lib/rubyXL/objects/sheet_data.rb +149 -0
  27. data/lib/rubyXL/objects/sheet_view.rb +71 -0
  28. data/lib/rubyXL/objects/stylesheet.rb +200 -0
  29. data/lib/rubyXL/objects/text.rb +87 -0
  30. data/lib/rubyXL/objects/theme.rb +64 -0
  31. data/lib/rubyXL/objects/workbook.rb +233 -0
  32. data/lib/rubyXL/objects/worksheet.rb +485 -0
  33. data/lib/rubyXL/parser.rb +78 -442
  34. data/lib/rubyXL/workbook.rb +216 -385
  35. data/lib/rubyXL/worksheet.rb +509 -1062
  36. data/lib/rubyXL/writer/content_types_writer.rb +104 -68
  37. data/lib/rubyXL/writer/core_writer.rb +26 -43
  38. data/lib/rubyXL/writer/generic_writer.rb +43 -0
  39. data/lib/rubyXL/writer/root_rels_writer.rb +11 -19
  40. data/lib/rubyXL/writer/styles_writer.rb +6 -398
  41. data/lib/rubyXL/writer/theme_writer.rb +321 -327
  42. data/lib/rubyXL/writer/workbook_writer.rb +63 -67
  43. data/lib/rubyXL/writer/worksheet_writer.rb +29 -218
  44. data/rdoc/created.rid +39 -0
  45. data/rdoc/fonts.css +167 -0
  46. data/rdoc/fonts/Lato-Light.ttf +0 -0
  47. data/rdoc/fonts/Lato-LightItalic.ttf +0 -0
  48. data/rdoc/fonts/Lato-Regular.ttf +0 -0
  49. data/rdoc/fonts/Lato-RegularItalic.ttf +0 -0
  50. data/rdoc/fonts/SourceCodePro-Bold.ttf +0 -0
  51. data/rdoc/fonts/SourceCodePro-Regular.ttf +0 -0
  52. data/rdoc/images/add.png +0 -0
  53. data/rdoc/images/arrow_up.png +0 -0
  54. data/rdoc/images/brick.png +0 -0
  55. data/rdoc/images/brick_link.png +0 -0
  56. data/rdoc/images/bug.png +0 -0
  57. data/rdoc/images/bullet_black.png +0 -0
  58. data/rdoc/images/bullet_toggle_minus.png +0 -0
  59. data/rdoc/images/bullet_toggle_plus.png +0 -0
  60. data/rdoc/images/date.png +0 -0
  61. data/rdoc/images/delete.png +0 -0
  62. data/rdoc/images/find.png +0 -0
  63. data/rdoc/images/loadingAnimation.gif +0 -0
  64. data/rdoc/images/macFFBgHack.png +0 -0
  65. data/rdoc/images/package.png +0 -0
  66. data/rdoc/images/page_green.png +0 -0
  67. data/rdoc/images/page_white_text.png +0 -0
  68. data/rdoc/images/page_white_width.png +0 -0
  69. data/rdoc/images/plugin.png +0 -0
  70. data/rdoc/images/ruby.png +0 -0
  71. data/rdoc/images/tag_blue.png +0 -0
  72. data/rdoc/images/tag_green.png +0 -0
  73. data/rdoc/images/transparent.png +0 -0
  74. data/rdoc/images/wrench.png +0 -0
  75. data/rdoc/images/wrench_orange.png +0 -0
  76. data/rdoc/images/zoom.png +0 -0
  77. data/rdoc/js/darkfish.js +140 -0
  78. data/rdoc/js/jquery.js +18 -0
  79. data/rdoc/js/navigation.js +142 -0
  80. data/rdoc/js/search.js +109 -0
  81. data/rdoc/js/search_index.js +1 -0
  82. data/rdoc/js/searcher.js +228 -0
  83. data/rdoc/rdoc.css +580 -0
  84. data/rubyXL.gemspec +90 -34
  85. data/spec/lib/cell_spec.rb +29 -59
  86. data/spec/lib/parser_spec.rb +35 -19
  87. data/spec/lib/reference_spec.rb +29 -0
  88. data/spec/lib/stylesheet_spec.rb +29 -0
  89. data/spec/lib/workbook_spec.rb +22 -17
  90. data/spec/lib/worksheet_spec.rb +47 -202
  91. metadata +185 -148
  92. data/lib/.DS_Store +0 -0
  93. data/lib/rubyXL/Hash.rb +0 -60
  94. data/lib/rubyXL/color.rb +0 -14
  95. data/lib/rubyXL/private_class.rb +0 -265
  96. data/lib/rubyXL/writer/app_writer.rb +0 -62
  97. data/lib/rubyXL/writer/calc_chain_writer.rb +0 -33
  98. data/lib/rubyXL/writer/shared_strings_writer.rb +0 -30
  99. data/lib/rubyXL/writer/workbook_rels_writer.rb +0 -59
  100. data/lib/rubyXL/zip.rb +0 -20
  101. data/spec/lib/hash_spec.rb +0 -28
@@ -0,0 +1,110 @@
1
+ module RubyXL
2
+ class Reference
3
+ ROW_MAX = 1024*1024
4
+ COL_MAX = 16393
5
+
6
+ attr_reader :row_range, :col_range
7
+
8
+ # RubyXL::Reference.new(row, col)
9
+ # RubyXL::Reference.new(row_from, row_to, col_from, col_to)
10
+ # RubyXL::Reference.new(reference_string)
11
+ def initialize(*params)
12
+ row_from = row_to = col_from = col_to = nil
13
+
14
+ case params.size
15
+ when 4 then row_from, row_to, col_from, col_to = params
16
+ when 2 then row_from, col_from = params
17
+ when 1 then
18
+ raise ArgumentError.new("invalid value for #{self.class}: #{params[0].inspect}") unless params[0].is_a?(String)
19
+ from, to = params[0].split(':')
20
+ row_from, col_from = self.class.ref2ind(from)
21
+ row_to, col_to = self.class.ref2ind(to) unless to.nil?
22
+ end
23
+
24
+ @row_range = Range.new(row_from || 0, row_to || row_from || ROW_MAX)
25
+ @col_range = Range.new(col_from || 0, col_to || col_from || COL_MAX)
26
+ end
27
+
28
+ def single_cell?
29
+ (@row_range.begin == @row_range.end) && (@col_range.begin == @col_range.end)
30
+ end
31
+
32
+ def first_row
33
+ @row_range.begin
34
+ end
35
+
36
+ def last_row
37
+ @row_range.end
38
+ end
39
+
40
+ def first_col
41
+ @col_range.begin
42
+ end
43
+
44
+ def last_col
45
+ @col_range.end
46
+ end
47
+
48
+ def ==(other)
49
+ !other.nil? && (@row_range == other.row_range) && (@col_range == other.col_range)
50
+ end
51
+
52
+ def cover?(other)
53
+ !other.nil? && (@row_range.cover?(other.row_range.begin) && @row_range.cover?(other.row_range.end) &&
54
+ @col_range.cover?(other.col_range.begin) && @col_range.cover?(other.col_range.end))
55
+ end
56
+
57
+ def to_s
58
+ if single_cell? then
59
+ self.class.ind2ref(@row_range.begin, @col_range.begin)
60
+ else
61
+ self.class.ind2ref(@row_range.begin, @col_range.begin) + ':' + self.class.ind2ref(@row_range.end, @col_range.end)
62
+ end
63
+ end
64
+
65
+ def inspect
66
+ if single_cell? then
67
+ "#<#{self.class} @row=#{@row_range.begin} @col=#{@col_range.begin}>"
68
+ else
69
+ "#<#{self.class} @row_range=#{@row_range} @col_range=#{@col_range}>"
70
+ end
71
+ end
72
+
73
+ # Converts +row+ and +col+ zero-based indices to Excel-style cell reference
74
+ # (0) A...Z, AA...AZ, BA... ...ZZ, AAA... ...AZZ, BAA... ...XFD (16383)
75
+ def self.ind2ref(row = 0, col = 0)
76
+ str = ''
77
+
78
+ loop do
79
+ x = col % 26
80
+ str = ('A'.ord + x).chr + str
81
+ col = (col / 26).floor - 1
82
+ break if col < 0
83
+ end
84
+
85
+ str += (row + 1).to_s
86
+ end
87
+
88
+ # Converts Excel-style cell reference to +row+ and +col+ zero-based indices.
89
+ def self.ref2ind(str)
90
+ return [ -1, -1 ] unless str =~ /^([A-Z]+)(\d+)$/
91
+
92
+ col = 0
93
+ $1.each_byte { |chr| col = col * 26 + (chr - 64) }
94
+ [ $2.to_i - 1, col - 1 ]
95
+ end
96
+
97
+ end
98
+
99
+ class Sqref < Array
100
+
101
+ def initialize(str)
102
+ str.split.each { |ref_str| self << RubyXL::Reference.new(ref_str) }
103
+ end
104
+
105
+ def to_s
106
+ self.collect{ |ref| ref.to_s }.join(' ')
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,59 @@
1
+ require 'rubyXL/objects/ooxml_object'
2
+
3
+ module RubyXL
4
+
5
+ class Relationship < OOXMLObject
6
+ define_attribute(:Id, :string)
7
+ define_attribute(:Type, :string)
8
+ define_attribute(:Target, :string)
9
+ define_element_name 'Relationship'
10
+ end
11
+
12
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_calcChain.html
13
+ class WorkbookRelationships < OOXMLObject
14
+ define_child_node(RubyXL::Relationship, :collection => true, :accessor => :relationships)
15
+ define_element_name 'Relationships'
16
+ set_namespaces('xmlns' => 'http://schemas.openxmlformats.org/package/2006/relationships')
17
+
18
+ attr_accessor :workbook
19
+
20
+ def create_relationship(target, type)
21
+ RubyXL::Relationship.new(:id => "rId#{relationships.size + 1}",
22
+ :type => "http://schemas.openxmlformats.org/officeDocument/2006/relationships/#{type}",
23
+ :target => target)
24
+ end
25
+
26
+ def before_write_xml
27
+ self.relationships = []
28
+
29
+ @workbook.worksheets.each_index { |i|
30
+ relationships << create_relationship("worksheets/sheet#{i + 1}.xml", 'worksheet')
31
+ }
32
+
33
+ @workbook.external_links.each_key { |k|
34
+ relationships << create_relationship("externalLinks/#{k}", 'externalLink')
35
+ }
36
+
37
+ relationships << create_relationship('theme/theme1.xml', 'theme')
38
+ relationships << create_relationship('styles.xml', 'styles')
39
+
40
+ if @workbook.shared_strings_container && !@workbook.shared_strings_container.strings.empty? then
41
+ relationships << create_relationship('sharedStrings.xml', 'sharedStrings')
42
+ end
43
+
44
+ if @workbook.calculation_chain && !@workbook.calculation_chain.cells.empty? then
45
+ relationships << create_relationship('calcChain.xml', 'calcChain')
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ def find_by_rid(r_id)
52
+ relationships.find { |r| r.id == r_id }
53
+ end
54
+
55
+ def self.filepath
56
+ File.join('xl', '_rels', 'workbook.xml.rels')
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,57 @@
1
+ require 'rubyXL/objects/ooxml_object'
2
+ require 'rubyXL/objects/text'
3
+ require 'rubyXL/objects/extensions'
4
+
5
+ module RubyXL
6
+
7
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_sst.html
8
+ class SharedStringsTable < OOXMLObject
9
+ # According to http://msdn.microsoft.com/en-us/library/office/gg278314.aspx,
10
+ # +count+ and +uniqueCount+ may be either both missing, or both present. Need to validate.
11
+ define_attribute(:uniqueCount, :int)
12
+ define_child_node(RubyXL::RichText, :collection => :with_count, :node_name => 'si', :accessor => :strings)
13
+ define_child_node(RubyXL::ExtensionStorageArea)
14
+ define_element_name 'sst'
15
+ set_namespaces('xmlns' => 'http://schemas.openxmlformats.org/spreadsheetml/2006/main')
16
+
17
+ def initialize(*params)
18
+ super
19
+ # So far, going by the structure that the original creator had in mind. However,
20
+ # since the actual implementation is now extracted into a separate class,
21
+ # we will be able to transparrently change it later if needs be.
22
+ @index_by_content = {}
23
+ end
24
+
25
+ def before_write_xml
26
+ super
27
+ self.unique_count = self.count
28
+ self.count > 0
29
+ end
30
+
31
+ def [](index)
32
+ strings[index]
33
+ end
34
+
35
+ def empty?
36
+ strings.empty?
37
+ end
38
+
39
+ def add(str, index = nil)
40
+ index ||= strings.size
41
+ strings[index] = RubyXL::Text.new(:value => str)
42
+ @index_by_content[str] = index
43
+ end
44
+
45
+ def get_index(str, add_if_missing = false)
46
+ index = @index_by_content[str]
47
+ index = add(str) if index.nil? && add_if_missing
48
+ index
49
+ end
50
+
51
+ def self.filepath
52
+ File.join('xl', 'sharedStrings.xml')
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,149 @@
1
+ require 'rubyXL/objects/ooxml_object'
2
+ require 'rubyXL/objects/text'
3
+ require 'rubyXL/objects/formula'
4
+
5
+ module RubyXL
6
+
7
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_v-1.html
8
+ class CellValue < OOXMLObject
9
+ define_attribute(:_, :string, :accessor => :value)
10
+ define_element_name 'v'
11
+ end
12
+
13
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_c-2.html
14
+ class Cell < OOXMLObject
15
+ define_attribute(:r, :ref)
16
+ define_attribute(:s, :int, :accessor => :style_index)
17
+ define_attribute(:t, :string, :accessor => :datatype, :default => 'n', :values => %w{ b n e s str inlineStr })
18
+ define_attribute(:cm, :int)
19
+ define_attribute(:vm, :int)
20
+ define_attribute(:ph, :bool)
21
+ define_child_node(RubyXL::Formula, :accessor => :formula)
22
+ define_child_node(RubyXL::CellValue, :accessor => :value_container)
23
+ define_child_node(RubyXL::RichText) # is
24
+ define_element_name 'c'
25
+
26
+ def index_in_collection
27
+ r.col_range.begin
28
+ end
29
+
30
+ def row
31
+ r && r.first_row
32
+ end
33
+
34
+ def row=(v)
35
+ self.r = RubyXL::Reference.new(v, column || 0)
36
+ end
37
+
38
+ def column
39
+ r && r.first_col
40
+ end
41
+
42
+ def column=(v)
43
+ self.r = RubyXL::Reference.new(row || 0, v)
44
+ end
45
+
46
+ def raw_value
47
+ value_container && value_container.value
48
+ end
49
+
50
+ def raw_value=(v)
51
+ self.value_container ||= RubyXL::CellValue.new
52
+ value_container.value = v
53
+ end
54
+
55
+ def value(args = {})
56
+ return raw_value if args[:raw]
57
+ case datatype
58
+ when RubyXL::Cell::SHARED_STRING then
59
+ workbook.shared_strings_container[raw_value.to_i]
60
+ else
61
+ if is_date? then workbook.num_to_date(raw_value.to_i)
62
+ else raw_value
63
+ end
64
+ end
65
+ end
66
+
67
+ include LegacyCell
68
+ end
69
+
70
+ #TODO#<row r="1" spans="1:1" x14ac:dyDescent="0.25">
71
+
72
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_row-1.html
73
+ class Row < OOXMLObject
74
+ define_attribute(:r, :int)
75
+ define_attribute(:spans, :string)
76
+ define_attribute(:s, :int)
77
+ define_attribute(:customFormat, :bool, :default => false)
78
+ define_attribute(:ht, :float)
79
+ define_attribute(:hidden, :bool, :default => false)
80
+ define_attribute(:customHeight, :bool, :default => false)
81
+ define_attribute(:outlineLevel, :int, :default => 0)
82
+ define_attribute(:collapsed, :bool, :default => false)
83
+ define_attribute(:thickTop, :bool, :default => false)
84
+ define_attribute(:thickBot, :bool, :default => false)
85
+ define_attribute(:ph, :bool, :default => false)
86
+ define_child_node(RubyXL::Cell, :collection => true, :accessor => :cells)
87
+ define_element_name 'row'
88
+
89
+ attr_accessor :worksheet
90
+
91
+ def index_in_collection
92
+ r - 1
93
+ end
94
+
95
+ def [](ind)
96
+ cells[ind]
97
+ end
98
+
99
+ def size
100
+ cells.size
101
+ end
102
+
103
+ def insert_cell_shift_right(c, col_index)
104
+ cells.insert(col_index, c)
105
+ col_index.upto(cells.size) { |col|
106
+ cell = cells[col]
107
+ next if cell.nil?
108
+ cell.column = col
109
+ }
110
+ end
111
+
112
+ def delete_cell_shift_left(col_index)
113
+ cells.delete_at(col_index)
114
+ col_index.upto(cells.size) { |col|
115
+ cell = cells[col]
116
+ next if cell.nil?
117
+ cell.column = col
118
+ }
119
+ end
120
+
121
+ def xf
122
+ @worksheet.workbook.cell_xfs[self.s || 0]
123
+ end
124
+
125
+ def get_fill_color
126
+ @worksheet.workbook.get_fill_color(xf)
127
+ end
128
+
129
+ def get_font
130
+ @worksheet.workbook.fonts[xf.font_id]
131
+ end
132
+ end
133
+
134
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_sheetData-1.html
135
+ class SheetData < OOXMLObject
136
+ define_child_node(RubyXL::Row, :collection => true, :accessor => :rows)
137
+ define_element_name 'sheetData'
138
+
139
+ def [](ind)
140
+ rows[ind]
141
+ end
142
+
143
+ def size
144
+ rows.size
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,71 @@
1
+ require 'rubyXL/objects/ooxml_object'
2
+
3
+ module RubyXL
4
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_pane-1.html
5
+ class Pane < OOXMLObject
6
+ define_attribute(:xSplit, :int)
7
+ define_attribute(:ySplit, :int)
8
+ define_attribute(:topLeftCell, :string)
9
+ define_attribute(:activePane, :string, :default => 'topLeft',
10
+ :values => %w{ bottomRight topRight bottomLeft topLeft })
11
+ define_attribute(:state, :string, :default=> 'split',
12
+ :values => %w{ split frozen frozenSplit })
13
+ define_element_name 'pane'
14
+ end
15
+
16
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_selection-1.html
17
+ class Selection < OOXMLObject
18
+ define_attribute(:pane, :string,
19
+ :values => %w{ bottomRight topRight bottomLeft topLeft })
20
+ define_attribute(:activeCell, :ref)
21
+ define_attribute(:activeCellId, :int) # 0-based index of @active_cell in @sqref
22
+ define_attribute(:sqref, :sqref) # Array of references to the selected cells.
23
+ define_element_name 'selection'
24
+
25
+ def before_write_xml
26
+ # Normally, rindex of activeCellId in sqref:
27
+ # <selection activeCell="E12" activeCellId="9" sqref="A4 B6 C8 D10 E12 A4 B6 C8 D10 E12"/>
28
+ if @active_cell_id.nil? && !@active_cell.nil? && @sqref.size > 1 then
29
+ # But, things can be more complex:
30
+ # <selection activeCell="E8" activeCellId="2" sqref="A4:B4 C6:D6 E8:F8"/>
31
+ # Not using .reverse.each here to avoid memory reallocation.
32
+ @sqref.each_with_index { |ref, ind| @active_cell_id = ind if ref.cover?(@active_cell) }
33
+ end
34
+ true
35
+ end
36
+ end
37
+
38
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_sheetView-1.html
39
+ class SheetView < OOXMLObject
40
+ define_attribute(:windowProtection, :bool, :default => false)
41
+ define_attribute(:showFormulas, :bool, :default => false)
42
+ define_attribute(:showGridLines, :bool, :default => true)
43
+ define_attribute(:showRowColHeaders, :bool, :default => true)
44
+ define_attribute(:showZeros, :bool, :default => true)
45
+ define_attribute(:rightToLeft, :bool, :default => false)
46
+ define_attribute(:tabSelected, :bool, :default => false)
47
+ define_attribute(:showRuler, :bool, :default => true)
48
+ define_attribute(:showOutlineSymbols, :bool, :default => true)
49
+ define_attribute(:defaultGridColor, :bool, :default => true)
50
+ define_attribute(:showWhiteSpace, :bool, :default => true)
51
+ define_attribute(:view, :string, :default => 'normal',
52
+ :values => %w{ normal pageBreakPreview pageLayout })
53
+ define_attribute(:topLeftCell, :ref)
54
+ define_attribute(:colorId, :int, :default => 64)
55
+ define_attribute(:zoomScale, :int, :default => 100)
56
+ define_attribute(:zoomScaleNormal, :int, :default => 0)
57
+ define_attribute(:zoomScaleSheetLayoutView, :bool, :default => 0)
58
+ define_attribute(:zoomScalePageLayoutView, :bool, :default => 0)
59
+ define_attribute(:workbookViewId, :int, :required => true, :default => 0 )
60
+ define_child_node(RubyXL::Pane)
61
+ define_child_node(RubyXL::Selection, :collection => true, :accessor => :selections )
62
+ define_element_name 'sheetView'
63
+ end
64
+
65
+ # http://www.schemacentral.com/sc/ooxml/e-ssml_sheetViews-3.html
66
+ class SheetViews < OOXMLObject
67
+ define_child_node(RubyXL::SheetView, :collection => true, :accessor => :sheet_views)
68
+ define_element_name 'sheetViews'
69
+ end
70
+
71
+ end