energon 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +7 -0
- data/README +31 -0
- data/lib/energon/document.rb +105 -0
- data/lib/energon/excel_document.rb +138 -0
- data/lib/energon/od_document.rb +90 -0
- data/lib/energon/open_document_helper.rb +65 -0
- data/lib/energon/open_xml_helper.rb +210 -0
- data/lib/energon/parser.rb +262 -0
- data/lib/energon/word_document.rb +94 -0
- data/lib/energon.rb +24 -0
- data/rakefile.rb +59 -0
- data/test/test_document.rb +150 -0
- data/test/test_excel_document.rb +36 -0
- data/test/test_oo_document.rb +49 -0
- data/test/test_open_document_helper.rb +55 -0
- data/test/test_open_xml_helper.rb +95 -0
- data/test/test_word_document.rb +36 -0
- metadata +86 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
|
4
|
+
module Woa; module Energon
|
5
|
+
|
6
|
+
class NoDataFound < StandardError #:nodoc:
|
7
|
+
end
|
8
|
+
class WrongData < StandardError #:nodoc:
|
9
|
+
end
|
10
|
+
|
11
|
+
# This class goal is to parse the placeholder, to make the correspondance with the right data
|
12
|
+
# and then to format the data according to the syntax extracted from the placeholder.
|
13
|
+
#
|
14
|
+
# Each placeholder is composed of a placeholder and a bunch of format functions.
|
15
|
+
#
|
16
|
+
# This class cannot be instanced. There is only one Class method: merge.
|
17
|
+
#
|
18
|
+
# == Placeholder
|
19
|
+
#
|
20
|
+
# The placeholder is composed by several names separated by a period (like Ruby Object syntax). (<tt>customer.name</tt>)
|
21
|
+
# For now only two members are permitted.
|
22
|
+
#
|
23
|
+
# Placeholders with only one name are static (<tt>author</tt>). They can only be replaced by a single data (<tt>"Jack Bauer"</tt>).
|
24
|
+
#
|
25
|
+
# Placeholders with two names are collections (+customer.name+). They are replaced by a bunch of data
|
26
|
+
# (<tt>["J. McGerol", "P. Fishno", "L. Rankka"]</tt>). If the second member is a plural, it means that the collection must be
|
27
|
+
# joined in a row and replace the placeholder (<tt>"J. McGerol, P. Fishno, L. Ranka"</tt>). The way that collections are imported
|
28
|
+
# depends on the type of exports used (see Document for more details).
|
29
|
+
#
|
30
|
+
# == Format Function
|
31
|
+
#
|
32
|
+
# Each placeholder can be added a set of functions separeted by a period. All format functions use the same syntax.
|
33
|
+
# A +f+ followed by a single caracter (parenthesa by default +(+ but could be anything). It takes then the syntax and
|
34
|
+
# finally the closed caracter (closed parenthesa by default +)+ but the same previously defined if not default).
|
35
|
+
# In all cases, the delimitors are echaped in the syntax.
|
36
|
+
#
|
37
|
+
# author.f(syntax1).f(syntax2)
|
38
|
+
# f(syntax \(here\)) => "syntax (here)"
|
39
|
+
# f/another syntax with another delimiter(\/)/ => "another syntax with another delimiter (/)"
|
40
|
+
#
|
41
|
+
# == Syntax
|
42
|
+
# Any kind of data can be used. By default, all data are interpreted as a String. Except the following types:
|
43
|
+
# * Numeric and its derivates
|
44
|
+
# * Date, DateTime and Time
|
45
|
+
# * Boolean
|
46
|
+
# * Array
|
47
|
+
# * Picture
|
48
|
+
#
|
49
|
+
# A syntax is possible for each type:
|
50
|
+
# ===String
|
51
|
+
#
|
52
|
+
# 0..N, end='' to limit the size of the string to N caracters.
|
53
|
+
# end is optionnal, its value by default is an empty string.
|
54
|
+
# If end is not empty and the original string has been truncated,
|
55
|
+
# end is added at the end of the new string.
|
56
|
+
# "Hello world".f(0..5, "...") => "Hello..."
|
57
|
+
#
|
58
|
+
# See String[http:www.ruby-doc.org/core/classes/String.html] class help for more details.
|
59
|
+
# * fixnum
|
60
|
+
# + str or << str or concat(str)
|
61
|
+
# [fixnum] or slice(fixnum)
|
62
|
+
# [fixnum, fixnum] or slice(fixnum, fixnum)
|
63
|
+
# [range] or slice(range)
|
64
|
+
# [regexp] or slice(regexp)
|
65
|
+
# [regexp, regexp] or slice(regexp, regexp)
|
66
|
+
# [str] or slice(str)
|
67
|
+
# capitalize
|
68
|
+
# center(integer, padstr)
|
69
|
+
# chomp(separator=$/)
|
70
|
+
# chop
|
71
|
+
# count([str]+)
|
72
|
+
# crypt(other_str)
|
73
|
+
# delete([str]+)
|
74
|
+
# downcase
|
75
|
+
# dump
|
76
|
+
# empty?
|
77
|
+
# equal(str) or == str or <==> str
|
78
|
+
# gsub(pattern, replacement)
|
79
|
+
# hash
|
80
|
+
# include(str)
|
81
|
+
# insert(index, str)
|
82
|
+
# inspect
|
83
|
+
# length
|
84
|
+
# ljust(integer, padstr='')
|
85
|
+
# lstrip
|
86
|
+
# succ or .next
|
87
|
+
# reverse
|
88
|
+
# rjust
|
89
|
+
# rstrip
|
90
|
+
# squeeze
|
91
|
+
# strip
|
92
|
+
# sub(pattern, replacement)
|
93
|
+
# swapcase
|
94
|
+
# tr(from_str, to_str)
|
95
|
+
# upcase
|
96
|
+
#
|
97
|
+
# ===Numeric
|
98
|
+
# str : str is format string using the sprintf syntax.
|
99
|
+
#
|
100
|
+
# See the following classes for more details:
|
101
|
+
# Numeric[http:www.ruby-doc.org/core/classes/Numeric.html],
|
102
|
+
# Integer[http:www.ruby-doc.org/core/classes/Integer.html],
|
103
|
+
# Fixnum[http:www.ruby-doc.org/core/classes/Fixnum.html],
|
104
|
+
# Bignum[http:www.ruby-doc.org/core/classes/Bignum.html] and
|
105
|
+
# Float[http:www.ruby-doc.org/core/classes/Float.html]
|
106
|
+
#
|
107
|
+
# + numeric
|
108
|
+
# - numeric
|
109
|
+
# * numeric
|
110
|
+
# ** numeric or power(numeric)
|
111
|
+
# << numeric
|
112
|
+
# >> numeric
|
113
|
+
# ^ numeric
|
114
|
+
# / numeric or .div(numeric)
|
115
|
+
# | numeric
|
116
|
+
# ~ numeric
|
117
|
+
# ceil
|
118
|
+
# div(numeric)
|
119
|
+
# eql?(numeric)
|
120
|
+
# floor
|
121
|
+
# gcd
|
122
|
+
# integer?
|
123
|
+
# lcm
|
124
|
+
# modulo(numeric) or % numeric
|
125
|
+
# next or succ
|
126
|
+
# remainder(numeric)
|
127
|
+
# round
|
128
|
+
# size
|
129
|
+
# truncate
|
130
|
+
# to_i (just for Floats)
|
131
|
+
# zero?
|
132
|
+
#
|
133
|
+
# ===DateTime
|
134
|
+
# See the following classes for more details:
|
135
|
+
# Time[http:www.ruby-doc.org/core/classes/Time.html],
|
136
|
+
# Date[http:www.ruby-doc.org/core/classes/Date.html] and
|
137
|
+
# DateTime[http:www.ruby-doc.org/core/classes/DateTime.html]
|
138
|
+
#
|
139
|
+
# + numeric
|
140
|
+
# - numeric
|
141
|
+
# << numeric
|
142
|
+
# << numeric
|
143
|
+
# hour
|
144
|
+
# min
|
145
|
+
# sec
|
146
|
+
# zone
|
147
|
+
# strftime
|
148
|
+
# httpdate
|
149
|
+
# asctime or ctime
|
150
|
+
# day or mday
|
151
|
+
# eql?(date)
|
152
|
+
# getlocal
|
153
|
+
# getgmt or getutc
|
154
|
+
# hour
|
155
|
+
# iso8601 or xmlschema
|
156
|
+
# localtime
|
157
|
+
# day
|
158
|
+
# min
|
159
|
+
# month
|
160
|
+
# rfc822 or rfc2822
|
161
|
+
# sec
|
162
|
+
# strftime(format) or format strftime("%d/%m/%y") <==> "%d/%m/%y"
|
163
|
+
# succ
|
164
|
+
# usec or tv_usec
|
165
|
+
# wday
|
166
|
+
# yday
|
167
|
+
# year
|
168
|
+
# zone
|
169
|
+
#
|
170
|
+
# ===Boolean
|
171
|
+
# ! : invert the boolean
|
172
|
+
#
|
173
|
+
# str_true, str_false : set the output for true and for false
|
174
|
+
# true.f("vrai", "faux") => "vrai"
|
175
|
+
# false.f/"vrai", "faux"/ => "vrai"
|
176
|
+
#
|
177
|
+
# ===Array
|
178
|
+
# delimitor, last_delimitor : set the delimitor for joining each elements of the Array and the last delimitor
|
179
|
+
# [1, 2, 3].f(", ", " and ") => "1, 2 and 3"
|
180
|
+
#
|
181
|
+
# ===Picture
|
182
|
+
# Not done yet!
|
183
|
+
#
|
184
|
+
# == Example
|
185
|
+
#
|
186
|
+
# Parser.merge("author.f(0..6).f(capitalize)", {:author => "JoHn Doe", :t1 => 1, :t2 => 2, :t3 => 3}) #"John"
|
187
|
+
#
|
188
|
+
# :include: rdoc-header
|
189
|
+
class Parser
|
190
|
+
def initialize #:nodoc:
|
191
|
+
raise Exception.new("Cannot create a new instance of this class")
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
# Find the corresponding data in datas and format it according to the placeholder name
|
196
|
+
# and placeholder format syntax. The final value is returned.
|
197
|
+
# 1. <tt>placeholder</tt>: a String representing a placeholder (xxx)
|
198
|
+
# 2. <tt>datas</tt> : a Hash of all the datas
|
199
|
+
def Parser.merge(placeholder, datas)
|
200
|
+
static, dynamic, format = Parser.extract_placeholder(placeholder)
|
201
|
+
specific = Parser.get_data(static, dynamic, datas)
|
202
|
+
# Apply format here
|
203
|
+
end
|
204
|
+
|
205
|
+
#########
|
206
|
+
private #
|
207
|
+
#########
|
208
|
+
|
209
|
+
def Parser.extract_placeholder(placeholder)
|
210
|
+
placeholder.scan(/^(\w+)(\.\w+)?(\.f.*)*$/) do |static, dynamic, format|
|
211
|
+
dynamic = dynamic.nil? ? nil : dynamic.to_s.gsub(/^\./, '')
|
212
|
+
format = format.nil? ? nil : format.to_s.gsub(/^\./, '')
|
213
|
+
return [static, dynamic, format]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def Parser.get_data(static, dynamic, datas)
|
218
|
+
raise NoPlaceholderFound if static.nil?
|
219
|
+
error = "placeholder '#{static + (dynamic.nil? ? '' : '.' + dynamic)}'"
|
220
|
+
|
221
|
+
specific_data = datas[static] rescue nil
|
222
|
+
if specific_data.nil?
|
223
|
+
specific_data = datas[static.to_sym] rescue nil
|
224
|
+
raise NoDataFound, error if specific_data.nil?
|
225
|
+
end
|
226
|
+
|
227
|
+
# static
|
228
|
+
raise WrongData if dynamic.nil? && specific_data.is_a?(Array)
|
229
|
+
return specific_data if dynamic.nil?
|
230
|
+
|
231
|
+
# dynamic
|
232
|
+
raise NoDataFound, error unless specific_data.is_a?(Array)
|
233
|
+
raise NoDataFound, error if specific_data.empty?
|
234
|
+
|
235
|
+
singular = Inflector::singularize(dynamic)
|
236
|
+
singular = nil if singular == dynamic
|
237
|
+
elements = []
|
238
|
+
|
239
|
+
value = dynamic
|
240
|
+
specific_data.each do |element|
|
241
|
+
method = element.method(value.to_sym) rescue nil
|
242
|
+
unless method.nil? || element.is_a?(Hash) # method
|
243
|
+
elements << method.call
|
244
|
+
else # array
|
245
|
+
elt = element[value.to_sym] rescue nil
|
246
|
+
elt = element[value] if elt.nil? rescue nil
|
247
|
+
if elt.nil?
|
248
|
+
raise NoDataFound, error if singular.nil? || value == singular
|
249
|
+
value = singular
|
250
|
+
retry
|
251
|
+
end
|
252
|
+
elements << elt
|
253
|
+
end
|
254
|
+
end
|
255
|
+
ret = elements
|
256
|
+
if value == singular
|
257
|
+
ret = elements.to_sentence(:skip_last_comma => true)
|
258
|
+
end
|
259
|
+
ret
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end; end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'energon/document'
|
2
|
+
require 'energon/open_xml_helper'
|
3
|
+
require 'rexml/document'
|
4
|
+
include REXML
|
5
|
+
|
6
|
+
module Woa; module Energon;
|
7
|
+
# This is a subclass of Document but it deals with Word templates
|
8
|
+
# instead of Text templates.
|
9
|
+
#
|
10
|
+
# Everything is the same as Document (Except the input and the output).
|
11
|
+
# See Document for more details.
|
12
|
+
#
|
13
|
+
# :include: rdoc-header
|
14
|
+
class WordDocument < Document
|
15
|
+
|
16
|
+
def write()
|
17
|
+
raise NoPlaceholderFound if @placeholders.empty?
|
18
|
+
rows = {}
|
19
|
+
@placeholders.each do |placeholder|
|
20
|
+
data = Parser.merge(placeholder[:placeholder], @datas)
|
21
|
+
element = placeholder[:element]
|
22
|
+
delimiter = placeholder[:delimiter]
|
23
|
+
if data.is_a?(Array)
|
24
|
+
row = XPath.first(element, 'ancestor::w:tr')
|
25
|
+
if row.nil?
|
26
|
+
element.text = element.text.to_s.gsub("#{delimiter}#{placeholder[:placeholder]}#{delimiter}", data.shift.to_s)
|
27
|
+
while !data.empty?
|
28
|
+
t = Element.new('w:t')
|
29
|
+
t.text = data.shift.to_s
|
30
|
+
element.parent.insert_after(element, t)
|
31
|
+
element.parent.insert_after(element, Element.new('w:br'))
|
32
|
+
element = t
|
33
|
+
end
|
34
|
+
else
|
35
|
+
rows[row] = [] if rows[row].nil?
|
36
|
+
rows[row] << {:element => element, :data => data}
|
37
|
+
end
|
38
|
+
else
|
39
|
+
element.text = element.text.to_s.gsub("#{delimiter}#{placeholder[:placeholder]}#{delimiter}", data.to_s)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rows.each do |row, cells|
|
43
|
+
continue = true
|
44
|
+
while continue
|
45
|
+
cells.each do |cell|
|
46
|
+
size = cell[:data].size
|
47
|
+
data = cell[:data].pop
|
48
|
+
element = cell[:element]
|
49
|
+
if data.nil?
|
50
|
+
continue = false
|
51
|
+
break
|
52
|
+
end
|
53
|
+
element.text = data
|
54
|
+
end
|
55
|
+
row.parent.insert_after(row, row.deep_clone) if continue
|
56
|
+
end
|
57
|
+
row.parent.delete(row)
|
58
|
+
end
|
59
|
+
@documents.each {|document| @openxml.save(document) }
|
60
|
+
@openxml.write
|
61
|
+
end
|
62
|
+
alias :close :write
|
63
|
+
|
64
|
+
#############################
|
65
|
+
private
|
66
|
+
#############################
|
67
|
+
def extract_placeholders
|
68
|
+
@openxml = OpenXmlHelper.new_word(@template)
|
69
|
+
@documents = @openxml.documents
|
70
|
+
@documents.each do |document|
|
71
|
+
XPath.each(document, '//w:t') do |element|
|
72
|
+
element.text.to_s.scan(Regexp.new("#{@delimiter}((#{Regexp.escape('\\' + @delimiter)}|[^#{@delimiter}])*)#{@delimiter}")) do |match, non_used|
|
73
|
+
@placeholders << {:placeholder => match, :element => element, :delimiter => @delimiter}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
XPath.each(document, '//w:t[text()]') do |element|
|
77
|
+
next unless Regexp.new("^(#{Regexp.escape('\\' + @delimiter)}|[^#{@delimiter}])*$") =~ element.text.to_s
|
78
|
+
placeholder = Regexp.last_match(0)
|
79
|
+
|
80
|
+
before = XPath.first(element, '../preceding-sibling::w:r/w:t[text()="' + @delimiter + '"]')
|
81
|
+
next if before.nil?
|
82
|
+
|
83
|
+
after = XPath.first(element, '../following-sibling::w:r')
|
84
|
+
next if after.nil?
|
85
|
+
after = XPath.first(after, 'w:t[text()="' + @delimiter + '"]')
|
86
|
+
next if after.nil?
|
87
|
+
before.parent.delete(before)
|
88
|
+
after.parent.delete(after)
|
89
|
+
@placeholders << {:placeholder => placeholder, :element => element, :delimiter => ''}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end; end
|
data/lib/energon.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'energon/document'
|
2
|
+
require 'energon/word_document'
|
3
|
+
require 'energon/excel_document'
|
4
|
+
require 'energon/open_xml_helper'
|
5
|
+
require 'energon/open_document_helper'
|
6
|
+
require 'energon/od_document'
|
7
|
+
|
8
|
+
require 'energon/parser'
|
9
|
+
|
10
|
+
|
11
|
+
# The Woa module contains all modules made by Woa! Kft.
|
12
|
+
#
|
13
|
+
# You can reach Woa! by visiting http://www.woa.hu or by mailing us to mailto:contact@woa.hu
|
14
|
+
#
|
15
|
+
# :include: rdoc-header
|
16
|
+
module Woa
|
17
|
+
# The Energon module contains all modules and classes used for the Energon projet (http://www.woa.hu).
|
18
|
+
#
|
19
|
+
# See README[link:files/README.html] for more details on Energon.
|
20
|
+
#
|
21
|
+
# :include: rdoc-header
|
22
|
+
module Energon
|
23
|
+
end
|
24
|
+
end
|
data/rakefile.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc "Run the tests"
|
9
|
+
Rake::TestTask::new do |t|
|
10
|
+
t.test_files = FileList['test/test_*.rb']
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Generate the documentation"
|
15
|
+
Rake::RDocTask::new do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'energon-doc/'
|
17
|
+
rdoc.title = "Energon Documentation"
|
18
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
19
|
+
rdoc.rdoc_files.include('README')
|
20
|
+
rdoc.rdoc_files.include('MIT-LICENSE')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
spec = Gem::Specification::new do |s|
|
25
|
+
s.platform = Gem::Platform::RUBY
|
26
|
+
|
27
|
+
s.name = 'energon'
|
28
|
+
s.version = "0.0.1"
|
29
|
+
s.summary = "Report engine outputting Word/Excel OpenXML documents"
|
30
|
+
s.description = <<EOF
|
31
|
+
Energon is a report engine written in ruby. It allows you to
|
32
|
+
create complex and reliable reports from your templates.
|
33
|
+
Both templates and output documents are based on OpenXML format.
|
34
|
+
Energon supports currently Text, Word and Excel documents.
|
35
|
+
EOF
|
36
|
+
s.author = 'Woa! Kft'
|
37
|
+
s.email = 'energon@woa.hu'
|
38
|
+
s.homepage = "http://www.woa.hu"
|
39
|
+
|
40
|
+
s.requirements << 'rubyzip, 0.9.1 or greater'
|
41
|
+
s.add_dependency('rubyzip', '>= 0.9.1')
|
42
|
+
|
43
|
+
s.requirements << 'activesupport, 1.3.1 or greater'
|
44
|
+
s.add_dependency('active_support', '>= 1.3.1')
|
45
|
+
|
46
|
+
s.require_path = 'lib'
|
47
|
+
s.files = FileList["lib/**/*.rb", "test/**/*.rb", "README","MIT-LICENSE","rakefile.rb"]
|
48
|
+
s.test_files = FileList['test/test*.rb']
|
49
|
+
|
50
|
+
s.has_rdoc = true
|
51
|
+
s.extra_rdoc_files = ["README"]
|
52
|
+
s.rdoc_options.concat ['--main', 'README']
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Package the library as a gem"
|
56
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
57
|
+
pkg.need_zip = true
|
58
|
+
pkg.need_tar = true
|
59
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'energon'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
include Woa::Energon
|
8
|
+
|
9
|
+
class TestDocument < Test::Unit::TestCase
|
10
|
+
|
11
|
+
# simple output with only one static placeholder
|
12
|
+
def test_static
|
13
|
+
document = Document.new("@test1@ bla")
|
14
|
+
document.add_value(:test1, "try it")
|
15
|
+
assert_equal("try it bla", document.write)
|
16
|
+
end
|
17
|
+
|
18
|
+
# simple output with two identic static placeholders
|
19
|
+
def test_static_parameter_twice
|
20
|
+
document = Document.new("@test1@ -- @test1@")
|
21
|
+
document.add_value(:test1, "try")
|
22
|
+
assert_equal("try -- try", document.write)
|
23
|
+
end
|
24
|
+
|
25
|
+
# multilines output with two identic static placeholders
|
26
|
+
def test_static_parameter_twice_multiline
|
27
|
+
document = Document.new("@test1@ -\n- @test1@")
|
28
|
+
document.add_value(:test1, "try")
|
29
|
+
assert_equal("try -\n- try", document.write)
|
30
|
+
end
|
31
|
+
|
32
|
+
# multilines output with only static placeholders
|
33
|
+
def test_static_parameters_multiline
|
34
|
+
document = Document.new("@test1@ bla \n @test2@ @test3@")
|
35
|
+
document.add_value(:test1, "try it")
|
36
|
+
document.add_values(:test2 => "test_2",
|
37
|
+
:test3 => 'test_3')
|
38
|
+
assert_equal("try it bla \n test_2 test_3", document.write)
|
39
|
+
end
|
40
|
+
|
41
|
+
# output without the data corresponding to the static placeholder
|
42
|
+
def test_static_missing
|
43
|
+
document = Document.new("@test1@ bla")
|
44
|
+
document.add_value(:non_existant_test, "try it")
|
45
|
+
assert_raise(NoDataFound) {document.write}
|
46
|
+
end
|
47
|
+
|
48
|
+
# simple output with a dynamic output in a Hash
|
49
|
+
def test_dynamic
|
50
|
+
document = Document.new("@test1.name@ bla")
|
51
|
+
document.add_value(:test1, [{:name => 'foo'},
|
52
|
+
{:name => 'bar'},
|
53
|
+
{:name => 'baz'}])
|
54
|
+
assert_equal("foo\nbar\nbaz bla", document.write)
|
55
|
+
end
|
56
|
+
|
57
|
+
# output with a missing dynamic field in one of the data in a Hash
|
58
|
+
def test_dynamic_missing_placeholder
|
59
|
+
document = Document.new("@test1.name@ bla")
|
60
|
+
document.add_value(:test1, [{:name => 'foo'},
|
61
|
+
{:name => 'bar'},
|
62
|
+
{:no_name => 'baz'}])
|
63
|
+
assert_raise(NoDataFound) {document.write}
|
64
|
+
end
|
65
|
+
|
66
|
+
# output with no data
|
67
|
+
def test_dynamic_no_data
|
68
|
+
document = Document.new("@test1.name@ bla")
|
69
|
+
document.add_value(:test1, [])
|
70
|
+
assert_raise(NoDataFound) {document.write}
|
71
|
+
end
|
72
|
+
|
73
|
+
# multiline output with dynamic placeholder and data in an Object
|
74
|
+
def test_dynamic_multiline_data
|
75
|
+
datas, names, logins = get_data
|
76
|
+
document = Document.new("@test1.name@\n====\n@test1.login@")
|
77
|
+
document.add_value(:test1, datas)
|
78
|
+
assert_equal("#{names}====#{logins}", document.write)
|
79
|
+
end
|
80
|
+
|
81
|
+
# multiline output with a missing data from an Object
|
82
|
+
def test_dynamic_multiline_missing_data
|
83
|
+
datas, names, logins = get_data
|
84
|
+
document = Document.new("@test1.name@\n====\n@test1.birthdate@")
|
85
|
+
document.add_value(:test1, datas)
|
86
|
+
assert_raise(NoDataFound) {document.write}
|
87
|
+
end
|
88
|
+
|
89
|
+
# delimiter different from the default one
|
90
|
+
def test_delimiter
|
91
|
+
datas, names, logins = get_data
|
92
|
+
document = Document.new("&test1.name&\n====\n&test1.login&", "&")
|
93
|
+
document.add_value(:test1, datas)
|
94
|
+
assert_equal("#{names}====#{logins}", document.write)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_invalid_delimiters
|
98
|
+
assert_raise EnergonError do
|
99
|
+
Document.new("&test1.name&\n====\n&test1.login&", "")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# multiline output with dynamic placeholder and data in an Object
|
104
|
+
def test_valid
|
105
|
+
datas, names, logins = get_data
|
106
|
+
|
107
|
+
document = Document.new("@test1.name@\n====\n@test1.login@")
|
108
|
+
assert(!document.valid?)
|
109
|
+
document.add_value(:test1, datas)
|
110
|
+
assert(document.valid?)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_no_placeholder
|
114
|
+
document = Document.new('foo bar ruby')
|
115
|
+
document.add_value(:test1, "Hello")
|
116
|
+
assert_raise(NoPlaceholderFound) { document.write }
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_plural
|
120
|
+
datas = []
|
121
|
+
datas << {:name => 'foo'}
|
122
|
+
datas << {:name => 'bar'}
|
123
|
+
datas << {:name => 'ruby'}
|
124
|
+
datas << {:name => 'woa'}
|
125
|
+
|
126
|
+
document = Document.new('@user.names@')
|
127
|
+
document.add_value(:user, datas)
|
128
|
+
assert_equal('foo, bar, ruby and woa', document.write)
|
129
|
+
end
|
130
|
+
|
131
|
+
###########################################################################
|
132
|
+
private
|
133
|
+
###########################################################################
|
134
|
+
|
135
|
+
# TODO: replace with yml file
|
136
|
+
def get_data
|
137
|
+
datas = []
|
138
|
+
names = ""
|
139
|
+
logins = ""
|
140
|
+
5.times do |i|
|
141
|
+
element = OpenStruct.new
|
142
|
+
element.name = "name#{i}"
|
143
|
+
element.login = "login#{i}"
|
144
|
+
datas << element
|
145
|
+
names << "name#{i}\n"
|
146
|
+
logins << "\nlogin#{i}"
|
147
|
+
end
|
148
|
+
return datas, names, logins
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'energon'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
include Woa::Energon
|
8
|
+
|
9
|
+
class TestExcelDocument < Test::Unit::TestCase
|
10
|
+
def test_1
|
11
|
+
FileUtils.cp('test/openxml/excel_template.xlsx', 'excel.xlsx')
|
12
|
+
excel = ExcelDocument.new('excel.xlsx', "%")
|
13
|
+
excel.add_value(:date, Time.now)
|
14
|
+
excel.add_value(:title, "Woa Title!")
|
15
|
+
excel.add_value(:footer, "Woa Footer!")
|
16
|
+
excel.add_value(:author, "Woa! Kft")
|
17
|
+
excel.add_value(:revision, 1.42)
|
18
|
+
|
19
|
+
elements = []
|
20
|
+
5.times do |i|
|
21
|
+
element = OpenStruct.new
|
22
|
+
element.date = Time.now + (rand * 10000000).to_i
|
23
|
+
element.login = "woa (#{i})"
|
24
|
+
element.name = "Woa! Kft (#{i})"
|
25
|
+
element.password = "******** (#{i})"
|
26
|
+
element.birthdate = Time.new + (rand * 10000000).to_i
|
27
|
+
element.address = "Kennedy st. (#{i})"
|
28
|
+
element.city = "Dallas (#{i})"
|
29
|
+
elements << element
|
30
|
+
end
|
31
|
+
|
32
|
+
excel.add_value('user', elements)
|
33
|
+
|
34
|
+
excel.close
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'energon'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
include Woa::Energon
|
9
|
+
|
10
|
+
class TestOdDocument < Test::Unit::TestCase
|
11
|
+
def test_word_and_excel
|
12
|
+
[{:ext => 'ods', :name => 'excel'}, {:ext => 'odt', :name => 'word'}].each do |hash|
|
13
|
+
orig = "test/opendocument/template.#{hash[:ext]}"
|
14
|
+
file = "#{hash[:name]}.#{hash[:ext]}"
|
15
|
+
|
16
|
+
FileUtils.cp(orig, file)
|
17
|
+
ods = OdDocument.new(file)
|
18
|
+
ods.add_value(:title, "Woa! Title")
|
19
|
+
ods.add_value(:date, "22/01/2007")
|
20
|
+
|
21
|
+
users = []
|
22
|
+
customers = []
|
23
|
+
5.times do |i|
|
24
|
+
user = OpenStruct.new
|
25
|
+
user.login = "login (#{i})"
|
26
|
+
user.firstname = "firstname (#{i})"
|
27
|
+
user.lastname = "lastname (#{i})"
|
28
|
+
users << user
|
29
|
+
|
30
|
+
customer = OpenStruct.new
|
31
|
+
customer.name = "name(#{i})"
|
32
|
+
customers << customer
|
33
|
+
end
|
34
|
+
|
35
|
+
ods.add_value(:customer, customers)
|
36
|
+
ods.add_value(:user, users)
|
37
|
+
ods.write
|
38
|
+
|
39
|
+
content_orig = content_new = nil
|
40
|
+
|
41
|
+
ZipFile.open("test/opendocument/template_test.#{hash[:ext]}") {|zipfile| content_orig = zipfile.file.read("content.xml")}
|
42
|
+
ZipFile.open(file) {|zipfile| content_new = zipfile.file.read("content.xml")}
|
43
|
+
|
44
|
+
assert_equal(content_orig, content_new)
|
45
|
+
|
46
|
+
FileUtils.rm(file)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|