xmlss 1.0.0.rc.1 → 1.0.0.rc.2
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/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
|