energon 0.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/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
|