xmlss 1.0.0.rc.1 → 1.0.0.rc.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +11 -8
- data/Rakefile +38 -19
- data/bench/bench_runner.rb +42 -0
- data/examples/layout.xml +0 -1
- data/examples/simple.xml +0 -1
- data/lib/xmlss/element/cell.rb +28 -23
- data/lib/xmlss/element/column.rb +0 -1
- data/lib/xmlss/element/row.rb +0 -1
- data/lib/xmlss/element/worksheet.rb +1 -1
- data/lib/xmlss/element_stack.rb +13 -19
- data/lib/xmlss/style/base.rb +0 -1
- data/lib/xmlss/style/font.rb +0 -2
- data/lib/xmlss/version.rb +1 -1
- data/lib/xmlss/workbook.rb +54 -20
- data/lib/xmlss/writer.rb +117 -89
- data/test/element/cell_test.rb +0 -7
- data/test/helper.rb +6 -17
- data/test/style/base_test.rb +1 -1
- data/test/style/font_test.rb +0 -1
- data/test/workbook_test.rb +2 -9
- data/test/writer_test.rb +25 -35
- data/xmlss.gemspec +3 -3
- metadata +17 -13
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,30 +1,33 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
xmlss (1.0.0.rc.
|
4
|
+
xmlss (1.0.0.rc.2)
|
5
5
|
enumeration (~> 1.3)
|
6
|
-
undies (~>
|
6
|
+
undies (~> 3.0.0.rc.1)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
|
-
ansi (1.4.
|
11
|
+
ansi (1.4.2)
|
12
12
|
assert (0.7.3)
|
13
13
|
assert-view (~> 0.5)
|
14
|
-
assert-view (0.
|
14
|
+
assert-view (0.6.0)
|
15
15
|
ansi (~> 1.3)
|
16
|
-
undies (~> 2.0)
|
17
16
|
enumeration (1.3.1)
|
18
17
|
rake (0.9.2)
|
19
18
|
ruby-prof (0.10.8)
|
20
|
-
undies (
|
19
|
+
undies (3.0.0.rc.1)
|
20
|
+
whysoslow (0.0.2)
|
21
|
+
ansi (~> 1.4)
|
21
22
|
|
22
23
|
PLATFORMS
|
23
24
|
ruby
|
24
25
|
|
25
26
|
DEPENDENCIES
|
26
|
-
assert (~> 0.
|
27
|
-
|
27
|
+
assert (~> 0.7.3)
|
28
|
+
assert-view (~> 0.6)
|
29
|
+
bundler (~> 1.1)
|
28
30
|
rake (~> 0.9.2)
|
29
31
|
ruby-prof
|
32
|
+
whysoslow (~> 0.0)
|
30
33
|
xmlss!
|
data/Rakefile
CHANGED
@@ -4,27 +4,46 @@ include Assert::RakeTasks
|
|
4
4
|
require 'bundler'
|
5
5
|
Bundler::GemHelper.install_tasks
|
6
6
|
|
7
|
-
task :default => :
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
7
|
+
task :default => :build
|
8
|
+
|
9
|
+
namespace :bench do
|
10
|
+
|
11
|
+
desc "Run the bench script."
|
12
|
+
task :run do
|
13
|
+
require 'bench/bench_runner'
|
14
|
+
XmlssBenchRunner.new(1000).run
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the profiler on 1000 rows."
|
18
|
+
task :profiler do
|
19
|
+
require 'bench/profiler_runner'
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
runner = XmlssProfilerRunner.new(1000)
|
22
|
+
runner.print_flat(STDOUT, :min_percent => 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Run the example workbook builds."
|
26
|
+
task :examples do
|
27
|
+
require 'examples/simple'
|
28
|
+
require 'examples/layout'
|
29
|
+
require 'examples/text'
|
30
|
+
require 'examples/styles'
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Run all the tests, then the profiler, then the bench."
|
34
|
+
task :all do
|
35
|
+
Rake::Task['test'].invoke
|
36
|
+
puts
|
37
|
+
Rake::Task['bench:profiler'].invoke
|
38
|
+
puts
|
39
|
+
Rake::Task['bench:run'].invoke
|
40
|
+
puts
|
41
|
+
Rake::Task['bench:examples'].invoke
|
42
|
+
end
|
20
43
|
|
21
|
-
runner = XmlssProfilerRunner.new(1000)
|
22
|
-
runner.print_flat(STDOUT, :min_percent => 3)
|
23
44
|
end
|
24
45
|
|
25
|
-
|
26
|
-
|
27
|
-
Rake::Task['test'].invoke
|
28
|
-
Rake::Task['run_examples'].invoke
|
29
|
-
Rake::Task['run_profiler'].invoke
|
46
|
+
task :bench do
|
47
|
+
Rake::Task['bench:run'].invoke
|
30
48
|
end
|
49
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'whysoslow'
|
2
|
+
require 'xmlss'
|
3
|
+
|
4
|
+
class XmlssBenchRunner
|
5
|
+
|
6
|
+
attr_reader :result
|
7
|
+
|
8
|
+
def initialize(n)
|
9
|
+
@build = Proc.new do
|
10
|
+
Xmlss::Workbook.new(Xmlss::Writer.new(:pp => 2), &Proc.new do
|
11
|
+
worksheet("5 columns, #{n} rows") {
|
12
|
+
column
|
13
|
+
column
|
14
|
+
column
|
15
|
+
column
|
16
|
+
column
|
17
|
+
|
18
|
+
n.times do |i|
|
19
|
+
row {
|
20
|
+
# put data into the row (infer type)
|
21
|
+
[1, "text", 123.45, "0001267", "$45.23"].each do |data_value|
|
22
|
+
cell { data data_value }
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end).to_file("./bench/profiler_#{n}.xml")
|
28
|
+
end
|
29
|
+
|
30
|
+
@printer = Whysoslow::DefaultPrinter.new({
|
31
|
+
:title => "#{n} rows",
|
32
|
+
:verbose => true
|
33
|
+
})
|
34
|
+
|
35
|
+
@runner = Whysoslow::Runner.new(@printer)
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
@runner.run &@build
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/examples/layout.xml
CHANGED
data/examples/simple.xml
CHANGED
data/lib/xmlss/element/cell.rb
CHANGED
@@ -7,8 +7,6 @@ module Xmlss::Element
|
|
7
7
|
def self.writer; :cell; end
|
8
8
|
|
9
9
|
attr_accessor :index, :style_id, :formula, :href, :merge_across, :merge_down
|
10
|
-
alias_method :style_i_d, :style_id
|
11
|
-
alias_method :h_ref, :href
|
12
10
|
|
13
11
|
attr_accessor :data
|
14
12
|
|
@@ -21,18 +19,14 @@ module Xmlss::Element
|
|
21
19
|
:error => "Error"
|
22
20
|
}
|
23
21
|
|
24
|
-
def initialize(*args
|
22
|
+
def initialize(*args)
|
25
23
|
attrs = args.last.kind_of?(::Hash) ? args.pop : {}
|
26
24
|
|
27
|
-
self.data = args.last.
|
28
|
-
self.
|
25
|
+
self.data = [args.last, attrs.delete(:data), ''].reject{|v| v.nil?}.first
|
26
|
+
self.merge_across = attrs.delete(:merge_across) || 0
|
27
|
+
self.merge_down = attrs.delete(:merge_down) || 0
|
29
28
|
|
30
|
-
self.
|
31
|
-
self.style_id = attrs[:style_id]
|
32
|
-
self.formula = attrs[:formula]
|
33
|
-
self.href = attrs[:href]
|
34
|
-
self.merge_across = attrs[:merge_across] || 0
|
35
|
-
self.merge_down = attrs[:merge_down] || 0
|
29
|
+
attrs.keys.each { |k| self.send("#{k}=", attrs[k]) }
|
36
30
|
end
|
37
31
|
|
38
32
|
def data=(v)
|
@@ -49,27 +43,38 @@ module Xmlss::Element
|
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
raise ArgumentError, "must specify #{meth} as a Fixnum"
|
56
|
-
end
|
57
|
-
instance_variable_set("@#{meth}", value && value <= 0 ? nil : value)
|
46
|
+
def index=(value)
|
47
|
+
if value && !value.kind_of?(::Fixnum)
|
48
|
+
raise ArgumentError, "must specify `index` as a Fixnum"
|
58
49
|
end
|
50
|
+
@index = (value && value <= 0 ? nil : value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def merge_across=(value)
|
54
|
+
if value && !value.kind_of?(::Fixnum)
|
55
|
+
raise ArgumentError, "must specify `merge_across` as a Fixnum"
|
56
|
+
end
|
57
|
+
@merge_across = (value && value <= 0 ? nil : value)
|
58
|
+
end
|
59
|
+
|
60
|
+
def merge_down=(value)
|
61
|
+
if value && !value.kind_of?(::Fixnum)
|
62
|
+
raise ArgumentError, "must specify `merge_down` as a Fixnum"
|
63
|
+
end
|
64
|
+
@merge_down = (value && value <= 0 ? nil : value)
|
59
65
|
end
|
60
66
|
|
61
67
|
private
|
62
68
|
|
63
69
|
def data_type(v)
|
64
|
-
|
65
|
-
|
70
|
+
if v.kind_of?(::String) || v.kind_of?(::Symbol)
|
71
|
+
:string
|
72
|
+
elsif v.kind_of?(::Numeric)
|
66
73
|
:number
|
67
|
-
|
74
|
+
elsif v.kind_of?(::Date) || v.kind_of?(::Time)
|
68
75
|
:date_time
|
69
|
-
|
76
|
+
elsif v.kind_of?(::TrueClass) || v.kind_of?(::FalseClass)
|
70
77
|
:boolean
|
71
|
-
when ::String, ::Symbol
|
72
|
-
:string
|
73
78
|
else
|
74
79
|
:string
|
75
80
|
end
|
data/lib/xmlss/element/column.rb
CHANGED
data/lib/xmlss/element/row.rb
CHANGED
data/lib/xmlss/element_stack.rb
CHANGED
@@ -12,7 +12,7 @@ module Xmlss
|
|
12
12
|
def initialize(writer, markup_type)
|
13
13
|
@stack = []
|
14
14
|
@writer = writer
|
15
|
-
@markup_type = markup_type
|
15
|
+
@markup_type = markup_type.to_s
|
16
16
|
@written_level = 0
|
17
17
|
end
|
18
18
|
|
@@ -24,44 +24,38 @@ module Xmlss
|
|
24
24
|
alias_method :current, :last
|
25
25
|
alias_method :level, :size
|
26
26
|
|
27
|
+
def using(element, &block)
|
28
|
+
push(element)
|
29
|
+
(block || Proc.new {}).call
|
30
|
+
pop
|
31
|
+
end
|
32
|
+
|
27
33
|
def push(element)
|
28
34
|
if @written_level < level
|
29
|
-
|
35
|
+
write(current)
|
36
|
+
@writer.push(@markup_type)
|
37
|
+
@written_level += 1
|
30
38
|
end
|
31
39
|
@stack.push(element)
|
32
40
|
end
|
33
41
|
|
34
42
|
def pop
|
35
43
|
if !empty?
|
36
|
-
|
37
|
-
@stack.pop.tap { |elem| write(elem) }
|
38
|
-
else
|
39
|
-
@stack.pop.tap { |elem| close(elem) }
|
40
|
-
end
|
44
|
+
@written_level < level ? write(@stack.pop) : close(@stack.pop)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
def using(element, &block)
|
45
|
-
push(element)
|
46
|
-
(block || Proc.new {}).call
|
47
|
-
pop
|
48
|
-
end
|
49
|
-
|
50
48
|
private
|
51
49
|
|
52
|
-
def open(element)
|
53
|
-
write(element)
|
54
|
-
@writer.push(@markup_type)
|
55
|
-
@written_level += 1
|
56
|
-
end
|
57
|
-
|
58
50
|
def close(element)
|
59
51
|
@writer.pop(@markup_type)
|
60
52
|
@written_level -= 1
|
53
|
+
element
|
61
54
|
end
|
62
55
|
|
63
56
|
def write(element)
|
64
57
|
@writer.write(element)
|
58
|
+
element
|
65
59
|
end
|
66
60
|
|
67
61
|
end
|
data/lib/xmlss/style/base.rb
CHANGED
data/lib/xmlss/style/font.rb
CHANGED
@@ -16,10 +16,8 @@ module Xmlss::Style
|
|
16
16
|
:subscript => 'Subscript',
|
17
17
|
:superscript => 'Superscript'
|
18
18
|
}
|
19
|
-
alias_method :vertical_align, :alignment
|
20
19
|
|
21
20
|
attr_accessor :bold, :color, :italic, :size, :strike_through, :shadow, :name
|
22
|
-
alias :font_name :name
|
23
21
|
|
24
22
|
def initialize(attrs={})
|
25
23
|
self.bold = attrs[:bold] || false
|
data/lib/xmlss/version.rb
CHANGED
data/lib/xmlss/workbook.rb
CHANGED
@@ -101,26 +101,60 @@ module Xmlss
|
|
101
101
|
|
102
102
|
# Workbook element attributes API
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
104
|
+
def data(value) # cell
|
105
|
+
self.class.worksheets_stack(self).current.data = value
|
106
|
+
end
|
107
|
+
|
108
|
+
def type(value) # cell
|
109
|
+
self.class.worksheets_stack(self).current.type = value
|
110
|
+
end
|
111
|
+
|
112
|
+
def index(value) # cell
|
113
|
+
self.class.worksheets_stack(self).current.index = value
|
114
|
+
end
|
115
|
+
|
116
|
+
def style_id(value) # cell, row, column
|
117
|
+
self.class.worksheets_stack(self).current.style_id = value
|
118
|
+
end
|
119
|
+
|
120
|
+
def formula(value) # cell
|
121
|
+
self.class.worksheets_stack(self).current.formula = value
|
122
|
+
end
|
123
|
+
|
124
|
+
def href(value) # cell
|
125
|
+
self.class.worksheets_stack(self).current.href = value
|
126
|
+
end
|
127
|
+
|
128
|
+
def merge_across(value) # cell
|
129
|
+
self.class.worksheets_stack(self).current.merge_across = value
|
130
|
+
end
|
131
|
+
|
132
|
+
def merge_down(value) # cell
|
133
|
+
self.class.worksheets_stack(self).current.merge_down = value
|
134
|
+
end
|
135
|
+
|
136
|
+
def height(value) # row
|
137
|
+
self.class.worksheets_stack(self).current.height = value
|
138
|
+
end
|
139
|
+
|
140
|
+
def auto_fit_height(value) # row
|
141
|
+
self.class.worksheets_stack(self).current.auto_fit_height = value
|
142
|
+
end
|
143
|
+
|
144
|
+
def hidden(value) # row, column
|
145
|
+
self.class.worksheets_stack(self).current.hidden = value
|
146
|
+
end
|
147
|
+
|
148
|
+
def width(value) # column
|
149
|
+
self.class.worksheets_stack(self).current.height = value
|
150
|
+
end
|
151
|
+
|
152
|
+
def auto_fit_width(value) # column
|
153
|
+
self.class.worksheets_stack(self).current.auto_fit_width = value
|
154
|
+
end
|
155
|
+
|
156
|
+
def name(value) # worksheet
|
157
|
+
self.class.worksheets_stack(self).current.name = value
|
124
158
|
end
|
125
159
|
|
126
160
|
# overriding to make less noisy
|
data/lib/xmlss/writer.rb
CHANGED
@@ -5,6 +5,7 @@ module Xmlss
|
|
5
5
|
class Writer
|
6
6
|
|
7
7
|
class Markup; end
|
8
|
+
class AttrsHash; end
|
8
9
|
|
9
10
|
# Xmlss uses Undies to stream its xml markup
|
10
11
|
# The Undies writer is responsible for driving the Undies API to generate
|
@@ -19,47 +20,14 @@ module Xmlss
|
|
19
20
|
NS_URI = "urn:schemas-microsoft-com:office:spreadsheet"
|
20
21
|
LB = " "
|
21
22
|
|
22
|
-
def self.attributes(thing, *attrs)
|
23
|
-
[*attrs].flatten.inject({}) do |xattrs, a|
|
24
|
-
xattrs.merge(if !(xv = self.coerce(thing.send(a))).nil?
|
25
|
-
{xmlss_attribute_name(a) => xv.to_s}
|
26
|
-
else
|
27
|
-
{}
|
28
|
-
end)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.xmlss_attribute_name(attr_name)
|
33
|
-
"#{SHEET_NS}:#{self.classify(attr_name)}"
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.classify(underscored_string)
|
37
|
-
underscored_string.
|
38
|
-
to_s.downcase.
|
39
|
-
split("_").
|
40
|
-
collect{|part| part.capitalize}.
|
41
|
-
join('')
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.coerce(value)
|
45
|
-
if value == true
|
46
|
-
1
|
47
|
-
elsif ["",false].include?(value)
|
48
|
-
# don't include false or empty string values
|
49
|
-
nil
|
50
|
-
else
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
23
|
attr_reader :styles_markup
|
56
24
|
attr_reader :worksheets_markup
|
57
25
|
|
58
26
|
def initialize(output_opts={})
|
59
27
|
@opts = output_opts || {}
|
60
28
|
|
61
|
-
@styles_markup = Markup.new(@opts.merge(:
|
62
|
-
@worksheets_markup = Markup.new(@opts.merge(:
|
29
|
+
@styles_markup = Markup.new(@opts.merge(:level => 2))
|
30
|
+
@worksheets_markup = Markup.new(@opts.merge(:level => 1))
|
63
31
|
end
|
64
32
|
|
65
33
|
def write(element)
|
@@ -87,103 +55,128 @@ module Xmlss
|
|
87
55
|
self.flush
|
88
56
|
"".tap do |markup|
|
89
57
|
Undies::Template.new(Undies::Source.new(Proc.new do
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
__partial styles
|
58
|
+
_ raw("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
|
59
|
+
__open_element("Workbook", XML_NS => NS_URI, "#{XML_NS}:#{SHEET_NS}" => NS_URI) {
|
60
|
+
__open_element("Styles") {
|
61
|
+
__partial @styles
|
94
62
|
}
|
95
|
-
__partial worksheets
|
63
|
+
__partial @worksheets
|
96
64
|
}
|
97
65
|
end), {
|
98
66
|
:styles => styles_markup.to_s,
|
99
67
|
:worksheets => worksheets_markup.to_s
|
100
|
-
}, Undies::
|
68
|
+
}, Undies::IO.new(markup, @opts))
|
101
69
|
end.strip
|
102
70
|
end
|
103
71
|
|
104
72
|
# workbook style markup directives
|
105
73
|
|
106
74
|
def alignment(alignment)
|
107
|
-
styles_markup.
|
108
|
-
|
109
|
-
|
75
|
+
styles_markup.inline_element("Alignment", AttrsHash.new.
|
76
|
+
value("Horizontal", alignment.horizontal).
|
77
|
+
value("Vertical", alignment.vertical).
|
78
|
+
value("Rotate", alignment.rotate).
|
79
|
+
bool( "WrapText", alignment.wrap_text).
|
80
|
+
raw
|
81
|
+
)
|
110
82
|
end
|
111
83
|
|
112
84
|
def border(border)
|
113
|
-
styles_markup.
|
114
|
-
|
115
|
-
|
85
|
+
styles_markup.inline_element("Border", AttrsHash.new.
|
86
|
+
value("Color", border.color).
|
87
|
+
value("Position", border.position).
|
88
|
+
value("Weight", border.weight).
|
89
|
+
value("LineStyle", border.line_style).
|
90
|
+
raw
|
91
|
+
)
|
116
92
|
end
|
117
93
|
|
118
94
|
def borders(borders)
|
119
|
-
styles_markup.
|
95
|
+
styles_markup.element("Borders", nil, {})
|
120
96
|
end
|
121
97
|
|
122
98
|
def font(font)
|
123
|
-
styles_markup.
|
124
|
-
|
125
|
-
|
126
|
-
|
99
|
+
styles_markup.inline_element("Font", AttrsHash.new.
|
100
|
+
bool( "Bold", font.bold).
|
101
|
+
value("Color", font.color).
|
102
|
+
bool( "Italic", font.italic).
|
103
|
+
value("Size", font.size).
|
104
|
+
bool( "Shadow", font.shadow).
|
105
|
+
value("FontName", font.name).
|
106
|
+
bool( "StrikeThrough", font.strike_through).
|
107
|
+
value("Underline", font.underline).
|
108
|
+
value("VerticalAlign", font.alignment).
|
109
|
+
raw
|
110
|
+
)
|
127
111
|
end
|
128
112
|
|
129
113
|
def interior(interior)
|
130
|
-
styles_markup.
|
131
|
-
|
132
|
-
|
114
|
+
styles_markup.inline_element("Interior", AttrsHash.new.
|
115
|
+
value("Color", interior.color).
|
116
|
+
value("Pattern", interior.pattern).
|
117
|
+
value("PatternColor", interior.pattern_color).
|
118
|
+
raw
|
119
|
+
)
|
133
120
|
end
|
134
121
|
|
135
122
|
def number_format(number_format)
|
136
|
-
|
137
|
-
|
138
|
-
]))
|
123
|
+
a = AttrsHash.new.value("Format", number_format.format).raw
|
124
|
+
styles_markup.inline_element("NumberFormat", a)
|
139
125
|
end
|
140
126
|
|
141
127
|
def protection(protection)
|
142
|
-
|
143
|
-
|
144
|
-
]))
|
128
|
+
a = AttrsHash.new.bool("Protect", protection.protect).raw
|
129
|
+
styles_markup.inline_element("Protection", a)
|
145
130
|
end
|
146
131
|
|
147
132
|
def style(style)
|
148
|
-
|
149
|
-
|
150
|
-
]))
|
133
|
+
a = AttrsHash.new.value("ID", style.id).raw
|
134
|
+
styles_markup.element("Style", nil, a)
|
151
135
|
end
|
152
136
|
|
153
137
|
# workbook element markup directives
|
154
138
|
|
155
139
|
def cell(cell)
|
156
140
|
# write the cell markup and push
|
157
|
-
worksheets_markup.
|
158
|
-
|
159
|
-
|
141
|
+
worksheets_markup.element("Cell", nil, AttrsHash.new.
|
142
|
+
value("Index", cell.index).
|
143
|
+
value("StyleID", cell.style_id).
|
144
|
+
value("Formula", cell.formula).
|
145
|
+
value("HRef", cell.href).
|
146
|
+
value("MergeAcross", cell.merge_across).
|
147
|
+
value("MergeDown", cell.merge_down).
|
148
|
+
raw
|
149
|
+
)
|
160
150
|
push(:worksheets)
|
161
151
|
|
162
152
|
# write nested data markup and push
|
163
|
-
worksheets_markup.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
# write data value
|
169
|
-
worksheets_markup.template.__ Undies::Template.
|
170
|
-
escape_html(cell.data_xml_value).
|
171
|
-
gsub(/(\r|\n)+/, LB)
|
153
|
+
worksheets_markup.element(
|
154
|
+
"Data",
|
155
|
+
worksheets_markup.raw(cell.data_xml_value),
|
156
|
+
AttrsHash.new.value("Type", cell.type).raw
|
157
|
+
)
|
172
158
|
|
173
159
|
pop(:worksheets)
|
174
|
-
pop(:worksheets)
|
175
160
|
end
|
176
161
|
|
177
162
|
def row(row)
|
178
|
-
worksheets_markup.
|
179
|
-
|
180
|
-
|
163
|
+
worksheets_markup.element("Row", nil, AttrsHash.new.
|
164
|
+
value("StyleID", row.style_id).
|
165
|
+
value("Height", row.height).
|
166
|
+
bool( "AutoFitHeight", row.auto_fit_height).
|
167
|
+
bool( "Hidden", row.hidden).
|
168
|
+
raw
|
169
|
+
)
|
181
170
|
end
|
182
171
|
|
183
172
|
def column(column)
|
184
|
-
worksheets_markup.
|
185
|
-
|
186
|
-
|
173
|
+
worksheets_markup.inline_element("Column", AttrsHash.new.
|
174
|
+
value("StyleID", column.style_id).
|
175
|
+
value("Width", column.width).
|
176
|
+
bool( "AutoFitWidth", column.auto_fit_width).
|
177
|
+
bool( "Hidden", column.hidden).
|
178
|
+
raw
|
179
|
+
)
|
187
180
|
end
|
188
181
|
|
189
182
|
def worksheet(worksheet)
|
@@ -191,30 +184,65 @@ module Xmlss
|
|
191
184
|
worksheets_markup.flush
|
192
185
|
|
193
186
|
# write the worksheet markup and push
|
194
|
-
|
195
|
-
|
196
|
-
]))
|
187
|
+
a = AttrsHash.new.value("Name", worksheet.name).raw
|
188
|
+
worksheets_markup.element("Worksheet", nil, a)
|
197
189
|
push(:worksheets)
|
198
190
|
|
199
191
|
# write the table container
|
200
|
-
worksheets_markup.
|
192
|
+
worksheets_markup.element("Table", nil, {})
|
201
193
|
end
|
202
194
|
|
203
195
|
end
|
204
196
|
|
205
197
|
|
206
198
|
|
199
|
+
class Writer::AttrsHash
|
200
|
+
|
201
|
+
attr_reader :raw
|
202
|
+
|
203
|
+
def initialize
|
204
|
+
@raw = Hash.new
|
205
|
+
end
|
206
|
+
|
207
|
+
def value(k, v)
|
208
|
+
# ignore any nil-value or empty string attrs
|
209
|
+
@raw["#{Xmlss::Writer::SHEET_NS}:#{k}"] = v if v && v != ''
|
210
|
+
self
|
211
|
+
end
|
212
|
+
|
213
|
+
def bool(k, v)
|
214
|
+
# write truthy values as '1', otherwise ignore
|
215
|
+
@raw["#{Xmlss::Writer::SHEET_NS}:#{k}"] = 1 if v
|
216
|
+
self
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
207
221
|
class Writer::Markup
|
208
222
|
|
209
223
|
attr_reader :template, :push_count, :pop_count
|
210
224
|
|
211
225
|
def initialize(opts={})
|
212
226
|
@markup = ""
|
213
|
-
@template = Undies::Template.new(Undies::
|
227
|
+
@template = Undies::Template.new(Undies::IO.new(@markup, opts))
|
214
228
|
@push_count = 0
|
215
229
|
@pop_count = 0
|
216
230
|
end
|
217
231
|
|
232
|
+
def raw(markup)
|
233
|
+
@template.raw(
|
234
|
+
Undies::Template.escape_html(markup).gsub(/(\r|\n)+/, Xmlss::Writer::LB)
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
def element(name, data, attrs)
|
239
|
+
@template.__open_element(name, data, attrs)
|
240
|
+
end
|
241
|
+
|
242
|
+
def inline_element(name, attrs)
|
243
|
+
@template.__closed_element(name, attrs)
|
244
|
+
end
|
245
|
+
|
218
246
|
def push
|
219
247
|
@push_count += 1
|
220
248
|
@template.__push
|
@@ -236,7 +264,7 @@ module Xmlss
|
|
236
264
|
def empty?; @markup.empty?; end
|
237
265
|
|
238
266
|
def to_s
|
239
|
-
@markup.to_s
|
267
|
+
@markup.to_s
|
240
268
|
end
|
241
269
|
|
242
270
|
end
|
data/test/element/cell_test.rb
CHANGED
@@ -15,7 +15,6 @@ module Xmlss::Element
|
|
15
15
|
should be_styled
|
16
16
|
should have_class_method :writer
|
17
17
|
should have_accessor :index, :formula, :href, :merge_across, :merge_down
|
18
|
-
should have_reader :h_ref
|
19
18
|
|
20
19
|
should have_enum :type, {
|
21
20
|
:number => "Number",
|
@@ -42,12 +41,6 @@ module Xmlss::Element
|
|
42
41
|
assert_equal "", subject.data
|
43
42
|
end
|
44
43
|
|
45
|
-
should "provide alias for :href" do
|
46
|
-
c = Cell.new({:href => "http://www.google.com"})
|
47
|
-
assert_equal "http://www.google.com", c.href
|
48
|
-
assert_equal "http://www.google.com", c.h_ref
|
49
|
-
end
|
50
|
-
|
51
44
|
should "bark when setting non Fixnum indices" do
|
52
45
|
assert_raises ArgumentError do
|
53
46
|
Cell.new({:index => "do it"})
|
data/test/helper.rb
CHANGED
@@ -6,26 +6,15 @@ $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
|
|
6
6
|
|
7
7
|
class Assert::Context
|
8
8
|
|
9
|
-
|
9
|
+
def self.be_styled
|
10
|
+
called_from = caller.first
|
11
|
+
Assert::Macro.new("have style attributes") do
|
12
|
+
should have_accessor :style_id
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
Assert::Macro.new("have style attributes") do
|
14
|
-
should have_accessor :style_id
|
15
|
-
should have_reader :style_i_d
|
16
|
-
|
17
|
-
should "set the style default" do
|
18
|
-
assert_equal nil, subject.class.new.style_id
|
19
|
-
end
|
20
|
-
|
21
|
-
should "provide aliases for style_id" do
|
22
|
-
c = subject.class.new({:style_id => :poo})
|
23
|
-
assert_equal :poo, c.style_id
|
24
|
-
assert_equal :poo, c.style_i_d
|
25
|
-
end
|
14
|
+
should "set the style default" do
|
15
|
+
assert_equal nil, subject.class.new.style_id
|
26
16
|
end
|
27
17
|
end
|
28
|
-
|
29
18
|
end
|
30
19
|
|
31
20
|
end
|
data/test/style/base_test.rb
CHANGED
data/test/style/font_test.rb
CHANGED
@@ -24,7 +24,6 @@ module Xmlss::Style
|
|
24
24
|
}
|
25
25
|
|
26
26
|
should have_class_method :writer
|
27
|
-
should have_reader :vertical_align
|
28
27
|
should have_accessors :bold, :color, :italic, :size, :strike_through
|
29
28
|
should have_accessors :shadow, :underline, :alignment, :name
|
30
29
|
should have_instance_methods :bold?, :italic?, :strike_through?, :shadow?
|
data/test/workbook_test.rb
CHANGED
@@ -39,13 +39,6 @@ module Xmlss::Worbook
|
|
39
39
|
assert_kind_of Xmlss::Style::Protection, subject.protection
|
40
40
|
end
|
41
41
|
|
42
|
-
should "not complain if setting an attribute when there's no current element" do
|
43
|
-
# it should just do nothing and go on
|
44
|
-
assert_nothing_raised do
|
45
|
-
subject.index(1)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
42
|
should "return workbook markup string" do
|
50
43
|
assert_match /<Workbook /, subject.to_s
|
51
44
|
end
|
@@ -83,7 +76,7 @@ module Xmlss::Worbook
|
|
83
76
|
end
|
84
77
|
|
85
78
|
assert_equal(
|
86
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"
|
79
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"><Styles><Style ss:ID=\"test\"><Alignment /><Borders><Border ss:LineStyle=\"Continuous\" ss:Weight=\"1\" /></Borders><Font /><Interior /><NumberFormat /><Protection /></Style></Styles><Worksheet ss:Name=\"test\"><Table><Column /><Row><Cell><Data ss:Type=\"Number\">#{wkbk.object_id}</Data></Cell></Row></Table></Worksheet></Workbook>",
|
87
80
|
wkbk.to_s
|
88
81
|
)
|
89
82
|
end
|
@@ -118,7 +111,7 @@ module Xmlss::Worbook
|
|
118
111
|
worksheet worksheet_name
|
119
112
|
end
|
120
113
|
assert_equal(
|
121
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"
|
114
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"><Styles></Styles><Worksheet ss:Name=\"awesome\"><Table></Table></Worksheet></Workbook>",
|
122
115
|
wkbk.to_s
|
123
116
|
)
|
124
117
|
end
|
data/test/writer_test.rb
CHANGED
@@ -14,7 +14,6 @@ module Xmlss
|
|
14
14
|
end
|
15
15
|
subject { @w }
|
16
16
|
|
17
|
-
should have_class_methods :attributes, :classify, :coerce
|
18
17
|
should have_readers :styles_markup, :worksheets_markup
|
19
18
|
should have_instance_methods :write, :push, :pop, :flush, :workbook
|
20
19
|
|
@@ -36,44 +35,35 @@ module Xmlss
|
|
36
35
|
|
37
36
|
|
38
37
|
|
39
|
-
class
|
38
|
+
class AttrsHashTests < BasicTests
|
39
|
+
desc "AttrsHash"
|
40
|
+
before do
|
41
|
+
@a = Writer::AttrsHash.new
|
42
|
+
end
|
43
|
+
subject { @a }
|
44
|
+
|
45
|
+
should have_reader :raw
|
46
|
+
should have_instance_methods :value, :bool
|
47
|
+
|
48
|
+
should "by default have an empty raw hash" do
|
49
|
+
assert_equal({}, subject.raw)
|
50
|
+
end
|
51
|
+
|
52
|
+
should "apply values to a raw hash with the writer namespace" do
|
53
|
+
assert_equal({"#{Writer::SHEET_NS}:a" => 'b'}, subject.value('a', 'b').raw)
|
54
|
+
end
|
40
55
|
|
41
|
-
should "
|
42
|
-
assert_equal
|
43
|
-
assert_nil Writer.coerce(false)
|
44
|
-
assert_nil Writer.coerce("")
|
45
|
-
assert_equal "hi", Writer.coerce("hi")
|
46
|
-
assert_equal 1, Writer.coerce(1)
|
56
|
+
should "ignore nil values" do
|
57
|
+
assert_equal({}, subject.value('a', nil).raw)
|
47
58
|
end
|
48
59
|
|
49
|
-
should "
|
50
|
-
assert_equal
|
51
|
-
assert_equal "Hi", Writer.classify("hi")
|
52
|
-
assert_equal "Hithere", Writer.classify("HiThere")
|
53
|
-
assert_equal "Hithere", Writer.classify("hithere")
|
54
|
-
assert_equal "HiThere", Writer.classify("Hi_There")
|
55
|
-
assert_equal "HiThere", Writer.classify("Hi_there")
|
56
|
-
assert_equal "HiThere", Writer.classify("hi_there")
|
60
|
+
should "ignore empty string values" do
|
61
|
+
assert_equal({}, subject.value('a', '').raw)
|
57
62
|
end
|
58
63
|
|
59
|
-
should "
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def thing; true; end
|
64
|
-
def other; false; end
|
65
|
-
def some; ""; end
|
66
|
-
def hi; :there; end
|
67
|
-
def hi_there; "you"; end
|
68
|
-
end
|
69
|
-
thing = Thing.new
|
70
|
-
exp = {
|
71
|
-
"ss:Hi" => "there",
|
72
|
-
"ss:HiThere" => "you",
|
73
|
-
"ss:Thing" => "1"
|
74
|
-
}
|
75
|
-
|
76
|
-
assert_equal exp, Writer.attributes(thing, thing.keys)
|
64
|
+
should "apply booleans as '1' and otherwise ignore" do
|
65
|
+
assert_equal({}, subject.bool('a', false).raw)
|
66
|
+
assert_equal({"#{Writer::SHEET_NS}:a" => 1}, subject.bool('a', true).raw)
|
77
67
|
end
|
78
68
|
|
79
69
|
end
|
@@ -392,7 +382,7 @@ Should
|
|
392
382
|
should "return workbook markup" do
|
393
383
|
build_workbook(subject)
|
394
384
|
assert_equal(
|
395
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"
|
385
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"><Styles><Style ss:ID=\"some_font\"><Font ss:Bold=\"1\" /></Style><Style ss:ID=\"some_numformat\"><NumberFormat ss:Format=\"General\" /></Style></Styles><Worksheet ss:Name=\"test1\"><Table><Row ss:Hidden=\"1\"><Cell ss:Index=\"2\"><Data ss:Type=\"String\">some data</Data></Cell></Row></Table></Worksheet><Worksheet ss:Name=\"test2\"><Table><Row ss:Hidden=\"1\"><Cell ss:Index=\"2\"><Data ss:Type=\"String\">some data</Data></Cell></Row></Table></Worksheet></Workbook>",
|
396
386
|
subject.workbook
|
397
387
|
)
|
398
388
|
end
|
data/xmlss.gemspec
CHANGED
@@ -17,8 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_development_dependency("
|
21
|
-
s.add_development_dependency("assert", ["~> 0.6"])
|
22
|
-
s.add_dependency("undies", ["~>
|
20
|
+
s.add_development_dependency("assert", ["~> 0.7.3"])
|
21
|
+
s.add_development_dependency("assert-view", ["~> 0.6"])
|
22
|
+
s.add_dependency("undies", ["~> 3.0.0.rc.1"])
|
23
23
|
s.add_dependency("enumeration", ["~> 1.3"])
|
24
24
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmlss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15424049
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
9
|
- 0
|
10
10
|
- rc
|
11
|
-
-
|
12
|
-
version: 1.0.0.rc.
|
11
|
+
- 2
|
12
|
+
version: 1.0.0.rc.2
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Kelly Redding
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2012-
|
20
|
+
date: 2012-04-17 00:00:00 Z
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
type: :development
|
@@ -26,12 +26,13 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 5
|
30
30
|
segments:
|
31
|
-
- 1
|
32
31
|
- 0
|
33
|
-
|
34
|
-
|
32
|
+
- 7
|
33
|
+
- 3
|
34
|
+
version: 0.7.3
|
35
|
+
name: assert
|
35
36
|
version_requirements: *id001
|
36
37
|
prerelease: false
|
37
38
|
- !ruby/object:Gem::Dependency
|
@@ -46,7 +47,7 @@ dependencies:
|
|
46
47
|
- 0
|
47
48
|
- 6
|
48
49
|
version: "0.6"
|
49
|
-
name: assert
|
50
|
+
name: assert-view
|
50
51
|
version_requirements: *id002
|
51
52
|
prerelease: false
|
52
53
|
- !ruby/object:Gem::Dependency
|
@@ -56,12 +57,14 @@ dependencies:
|
|
56
57
|
requirements:
|
57
58
|
- - ~>
|
58
59
|
- !ruby/object:Gem::Version
|
59
|
-
hash:
|
60
|
+
hash: 15424119
|
60
61
|
segments:
|
61
|
-
-
|
62
|
-
-
|
62
|
+
- 3
|
63
|
+
- 0
|
64
|
+
- 0
|
65
|
+
- rc
|
63
66
|
- 1
|
64
|
-
version:
|
67
|
+
version: 3.0.0.rc.1
|
65
68
|
name: undies
|
66
69
|
version_requirements: *id003
|
67
70
|
prerelease: false
|
@@ -95,6 +98,7 @@ files:
|
|
95
98
|
- Gemfile.lock
|
96
99
|
- README.rdoc
|
97
100
|
- Rakefile
|
101
|
+
- bench/bench_runner.rb
|
98
102
|
- bench/profiler.rb
|
99
103
|
- bench/profiler_runner.rb
|
100
104
|
- examples/example_workbook.rb
|