libexcel 0.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.
data/lib/libexcel.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'libxml'
2
+ require 'libexcel/document'
3
+ require 'libexcel/worksheet'
4
+ require 'libexcel/formula'
5
+
6
+ module LibExcel
7
+
8
+ VERSION = "0.1"
9
+
10
+ class << self
11
+
12
+ # Creates the full Excel XML equation string
13
+ #
14
+ # @return [String] the full Excel style equation string
15
+ def range(args)
16
+ if args[:cols].nil?
17
+ (buf = static(args[:rows].first, args[:col])) << ':'
18
+ buf << static(args[:rows].last, args[:col])
19
+ elsif args[:rows].nil?
20
+ (buf = static(args[:row], args[:cols].first)) << ':'
21
+ buf << static(args[:row], args[:cols].last)
22
+ else
23
+ (buf = static(args[:rows].first, args[:cols].first)) << ':'
24
+ buf << static(args[:rows].last, args[:cols].last)
25
+ end
26
+ end
27
+
28
+ # Creates part of the Excel XML style equation string
29
+ #
30
+ # @example
31
+ # static(1, 1) => "R[1]C[1]"
32
+ # static(0, 1) => "R[0]C[1]"
33
+ # static(1) => "R[1]C"
34
+ # static(nil, 1) => "RC[1]"
35
+ #
36
+ # @param [Integer, Integer] the two integer values to be converted
37
+ # @return [String] the Excel style equation string
38
+ def static(row, col)
39
+ if col.nil?
40
+ "R[#{row}]C"
41
+ elsif row.nil?
42
+ "RC[#{col}]"
43
+ else
44
+ "R[#{row}]C[#{col}]"
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,86 @@
1
+ module LibExcel
2
+
3
+ # The Document class manages the document section of the Excel XML file.
4
+ class Document < LibXML::XML::Document
5
+ include LibXML
6
+
7
+ attr_accessor :name
8
+
9
+ # Creates the Document object. Calls the +super()+ to get the basics of a
10
+ # XML document. +name+ is the name of the document.
11
+ def initialize(name)
12
+ super()
13
+
14
+ @name = name
15
+ build_document
16
+ build_root
17
+ end
18
+
19
+ # Appends a worksheet to a Document. Requires that they worksheet being
20
+ # appended to the document be a Worksheet.
21
+ #
22
+ # @return [Document] the Full XML document
23
+ def <<(worksheet)
24
+ if not worksheet.is_a? Worksheet
25
+ raise ArgumentError, "Need to have a Excel::Worksheet"
26
+ end
27
+ root << worksheet
28
+ end
29
+
30
+ private
31
+ def root
32
+ super
33
+ end
34
+
35
+ # Setup the common Excel URIs in the root.
36
+ def build_document
37
+ self.root = XML::Node.new('Workbook')
38
+ root['xmlns'] = 'urn:schemas-microsoft-com:office:spreadsheet'
39
+ root['xmlns:o'] = 'urn:schemas-microsoft-com:office:office'
40
+ root['xmlns:x'] = 'urn:schemas-microsoft-com:office:excel'
41
+ root['xmlns:ss'] = 'urn:schemas-microsoft-com:office:spreadsheet'
42
+ root['xmlns:html'] = 'http://www.w3.org/TR/REC-html40'
43
+ end
44
+
45
+ # Setup the document properties of the document.
46
+ def build_root
47
+ root << document_properties = XML::Node.new('DocumentProperties')
48
+ document_properties['xmlns'] = 'urn:schemas-microsoft-com:office:office'
49
+
50
+ document_properties << author = XML::Node.new('Author')
51
+ author << 'Scarlet'
52
+ document_properties << last_author = XML::Node.new('LastAuthor')
53
+ last_author << 'Scarlet'
54
+ document_properties << version = XML::Node.new('Version')
55
+ version << '12.256'
56
+
57
+ root << office_document_settings = XML::Node.new('OfficeDocumentSettings')
58
+ office_document_settings['xmlns'] = 'urn:schemas-microsoft-com:office:office'
59
+ office_document_settings << XML::Node.new('AllowPNG')
60
+
61
+ root << excel_workbook = XML::Node.new('ExcelWorkbook')
62
+ excel_workbook['xmlns'] = 'urn:schemas-microsoft-com:office:excel'
63
+
64
+ excel_workbook << window_height = XML::Node.new('WindowHeight', '20260')
65
+ excel_workbook << window_width = XML::Node.new('WindowWidth', '29600')
66
+ excel_workbook << window_top_x = XML::Node.new('WindowTopX', '3440')
67
+ excel_workbook << window_top_y = XML::Node.new('WindowTopY', '-80')
68
+ excel_workbook << XML::Node.new('Date1904')
69
+ excel_workbook << XML::Node.new('ProtectStructure', 'False')
70
+ excel_workbook << XML::Node.new('ProtectWindows', 'False')
71
+
72
+ root << styles = XML::Node.new('Styles')
73
+ styles << style = XML::Node.new('Style')
74
+ style['ss:ID'] = 'Default'
75
+ style['ss:Name'] = 'Normal'
76
+ style << alignment = XML::Node.new('Alignment')
77
+ alignment['ss:Vertical'] = 'Bottom'
78
+ style << XML::Node.new('Borders')
79
+ style << font = XML::Node.new('Font')
80
+ font['ss:FontName'] = 'Verdana'
81
+ style << XML::Node.new('Interior')
82
+ style << XML::Node.new('NumberFormat')
83
+ style << XML::Node.new('Protection')
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,82 @@
1
+ module LibExcel
2
+ # Manages a Formula object to be used in a {Excel::Worksheet}.
3
+ # Builds an Excel XML formula. The Formula class responds to any
4
+ # +class method+. Such methods should correspond to their Excel
5
+ # counterparts.
6
+ #
7
+ # Some Excel formulas that will work are:
8
+ # * COUNTA
9
+ # * SUM
10
+ # * etc.
11
+ #
12
+ # @example
13
+ # formula = Excel::Formula.counta(:row => 1..2)
14
+ # # Creates an equivalent formula =COUNTA(1:2)
15
+ #
16
+ class Formula
17
+ attr_reader :xml
18
+
19
+ # <b>Should never be called directly.</b>
20
+ # Creates the Formula object
21
+ def initialize(equ)
22
+ @xml = LibXML::XML::Node.new('Cell')
23
+ @xml['ss:Formula'] = equ
24
+ end
25
+
26
+ # Creates a new Formula thats references the division of one Formula
27
+ # by another Formula.
28
+ #
29
+ # @return [Formula] A new Formula reference
30
+ #
31
+ # @example
32
+ # f1 = Excel::Formula.counta(:row => 1..2)
33
+ # f2 = Excel::Formula.counta(:row => 1..2)
34
+ # f1_divided_f2 = f1/f1
35
+ def /(formula)
36
+ org_f = self.xml['ss:Formula']
37
+ org_f << '/' << formula.xml['ss:Formula'][1..-1]
38
+ Formula.new(org_f)
39
+ end
40
+
41
+ def self.node_correct?(node)
42
+ digit_block = /(\[-?\d+\])?/
43
+ r_d_block = /R#{digit_block}C#{digit_block}/
44
+ function = /=[A-Z]+\(#{r_d_block}:#{r_d_block}\)/
45
+
46
+ (node['ss:Formula'] =~ function) != nil
47
+ end
48
+
49
+ def self.partition(node)
50
+ digit_block = /(\[-?\d+\])?/
51
+ big_block = /R#{digit_block}C#{digit_block}:R#{digit_block}C#{digit_block}/
52
+
53
+ m = big_block.match(node['ss:Formula']).to_a[1..4]
54
+ m.map { |bits| bits.nil? ? nil : bits[1..-2].to_i }
55
+ end
56
+
57
+ # A class method that is a catchall for equation names.
58
+ def self.method_missing(meth, *args)
59
+ buffer = "=#{meth.to_s.upcase}(#{LibExcel.range(args.first)})"
60
+
61
+ self.new(buffer)
62
+ end
63
+
64
+ private
65
+ # @deprecated This isn't used in production but still help here
66
+ # for testings purposes.
67
+ #
68
+ # @see Excel.range for the actually production impl
69
+ def self.build_formula(hash)
70
+ if hash.is_a? Hash
71
+ buffer = ""
72
+ buffer << (hash.include?(:r) ? "R[#{hash[:r]}]" : "R")
73
+ buffer << (hash.include?(:c) ? "C[#{hash[:c]}]" : "C")
74
+ buffer << (hash.include?(:r2) ? ":R[#{hash[:r2]}]" : ":R")
75
+ buffer << (hash.include?(:c2) ? "C[#{hash[:c2]}]" : "C")
76
+ else
77
+ buffer = "RC:RC"
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,103 @@
1
+ module LibExcel
2
+ # Manages the worksheet of an {Excel::Document}
3
+ #
4
+ # A Worksheet works by first creating a row then by adding one cell
5
+ # at a time until you call +add_row+ again to start on a new row.
6
+ #
7
+ # @example Create a Worksheet and add "hello world" to the first cell.
8
+ # worksheet = Excel::Worksheet.new('My worksheet')
9
+ # worksheet.add_row
10
+ # worksheet.add_cell("hello world")
11
+ class Worksheet < LibXML::XML::Node
12
+ include LibXML
13
+ alias_method :append, :<<
14
+
15
+ DEFAULT_COLUMN_WIDTH = '100'
16
+
17
+ # Creates the Worksheet object. +name+ is the name of the Excel Document Tab. +name+ gets truncated to 31 chars.
18
+ def initialize(name)
19
+ super('Worksheet')
20
+ # Excel complains if the name is more than 31 chars.
21
+ self['ss:Name'] = name[0..30]
22
+ self.append table
23
+ @f_column = XML::Node.new('Column')
24
+ @f_column['ss:Width'] = DEFAULT_COLUMN_WIDTH
25
+ @table << @f_column
26
+ end
27
+
28
+ def name
29
+ self['ss:Name']
30
+ end
31
+
32
+ def f_column
33
+ @f_column['ss:Width']
34
+ end
35
+
36
+ # Sets the +name+ and retuncates it to 31 chars.
37
+ def name=(name)
38
+ self['ss:Name'] = name[0..30]
39
+ end
40
+
41
+ def f_column=(value)
42
+ @f_column['ss:Width'] = value.to_s
43
+ end
44
+
45
+ # Creates a row in the Worksheet. This needs to be called before
46
+ # you can add data to the Worksheet.
47
+ def add_row
48
+ @table << @row = XML::Node.new('Row')
49
+ end
50
+
51
+ def add_cell(raw_data, attributes = {})
52
+ @row << cell = XML::Node.new('Cell')
53
+ if attributes[:formula]
54
+ cell['ss:Formula'] = attributes[:formula]
55
+ elsif not raw_data.nil?
56
+ cell << data = XML::Node.new('Data')
57
+ if raw_data.is_a?(Fixnum) or raw_data.is_a?(Float)
58
+ data['ss:Type'] = 'Number'
59
+ elsif raw_data.is_a? String
60
+ data['ss:Type'] = 'String'
61
+ end
62
+
63
+ data << raw_data
64
+ else
65
+ cell << data = XML::Node.new('Data')
66
+ data['ss:Type'] = 'String'
67
+ data << raw_data
68
+ end
69
+ data
70
+ end
71
+
72
+ # A helper method to add an array of data to the Worksheet.
73
+ #
74
+ # @param [Array] the Array of Objects being appended to the Worksheet.
75
+ def add_array(array)
76
+ for item in array
77
+ self.add_cell(item)
78
+ end
79
+ end
80
+
81
+ # Append anything that responds to +:xml+ to the Worksheet
82
+ def <<(raw_data)
83
+ if !raw_data.respond_to?(:xml)
84
+ raise ArgumentError, "Need to have a Excel::Formula"
85
+ end
86
+ @row << raw_data.xml
87
+ end
88
+
89
+ # Creates a reference to a cell in this Worksheet to be used in
90
+ # another Worksheet.
91
+ def reference(args, equal = '=')
92
+ Formula.new("#{equal}'#{name}'!#{LibExcel.static(args[:row], args[:col])}")
93
+ end
94
+
95
+ private
96
+ def table
97
+ table = XML::Node.new('Table')
98
+ table['x:FullColumns'] = '1'
99
+ table['x:FullRows'] = '1'
100
+ @table = table
101
+ end
102
+ end
103
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libexcel
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Silas Baronda
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-02-27 00:00:00 -05:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: libxml-ruby
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 1
28
+ - 1
29
+ - 3
30
+ version: 1.1.3
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description:
34
+ email:
35
+ - silas.baronda@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/libexcel.rb
44
+ - lib/libexcel/worksheet.rb
45
+ - lib/libexcel/document.rb
46
+ - lib/libexcel/formula.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/silasb/libexcel
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 1
69
+ - 3
70
+ - 5
71
+ version: 1.3.5
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.6
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: XML Excel library for ruby
79
+ test_files: []
80
+