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 +50 -0
- data/lib/libexcel/document.rb +86 -0
- data/lib/libexcel/formula.rb +82 -0
- data/lib/libexcel/worksheet.rb +103 -0
- metadata +80 -0
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
|
+
|