odf-report 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +21 -3
- data/lib/odf-report.rb +9 -5
- data/lib/odf-report/file_ops.rb +13 -0
- data/lib/odf-report/hash_gsub.rb +6 -0
- data/lib/odf-report/images.rb +37 -0
- data/lib/odf-report/nested.rb +42 -0
- data/lib/odf-report/report.rb +30 -57
- data/lib/odf-report/section.rb +56 -76
- data/lib/odf-report/table.rb +45 -80
- data/odf-report.gemspec +6 -3
- metadata +52 -58
- data/test/test.odt +0 -0
- data/test/test.rb +0 -78
data/README.textile
CHANGED
@@ -3,11 +3,20 @@ h1. ODF-REPORT
|
|
3
3
|
Gem for generating .odt files by making strings, images, tables and sections replacements in a previously created .odt file.
|
4
4
|
|
5
5
|
|
6
|
+
h2. NEW!
|
7
|
+
|
8
|
+
<pre>
|
9
|
+
ODF-REPORT have been internally refactored. It now uses Nokogiri for parsing the documents, instead of Regex.
|
10
|
+
|
11
|
+
This provides for a much greater flexibility. As a result, I was able to implement nested sections.
|
12
|
+
|
13
|
+
Now sections can be nested inside sections, with fields, tables and others sections.
|
14
|
+
</pre>
|
15
|
+
|
6
16
|
h2. INSTALL
|
7
17
|
|
8
18
|
(sudo) gem install odf-report
|
9
19
|
|
10
|
-
|
11
20
|
h2. USAGE
|
12
21
|
|
13
22
|
h3. Step 1 -- the template
|
@@ -96,11 +105,11 @@ end
|
|
96
105
|
</pre>
|
97
106
|
|
98
107
|
|
99
|
-
h3. Sections
|
108
|
+
h3. Sections
|
100
109
|
|
101
110
|
Sometimes, you have to repeat a whole chunk of a document, in a structure a lot more complex than a table. Now you can make a Section in your template and use it in this situations. Creating a Session in OpenOffice is as easy as select menu *Insert* and then *Section...*, and then choose a name for it.
|
102
111
|
|
103
|
-
*Section* 's are lot like Tables, in the sense that you can pass a collection and have that section repeated for each member of the collection. *But*, Sections can have anything inside it, even Tables
|
112
|
+
*Section* 's are lot like Tables, in the sense that you can pass a collection and have that section repeated for each member of the collection. *But*, Sections can have anything inside it, even Tables *and nested Sections*, as long as you pass the appropriate data structure.
|
104
113
|
|
105
114
|
Let's see an example:
|
106
115
|
|
@@ -133,6 +142,14 @@ Let's see an example:
|
|
133
142
|
end
|
134
143
|
end
|
135
144
|
|
145
|
+
s.add_section("SUB_NOTES", :notes) do |s1|
|
146
|
+
|
147
|
+
s1.add_field(:note_title) { |n| n.title }
|
148
|
+
|
149
|
+
s1.add_table ...
|
150
|
+
|
151
|
+
end
|
152
|
+
|
136
153
|
end
|
137
154
|
|
138
155
|
end
|
@@ -208,6 +225,7 @@ report.generate("./documents/")
|
|
208
225
|
h3. REQUIREMENTS
|
209
226
|
|
210
227
|
*rubyzip*: for manipulating the contents of the odt file, since it's actually a zip file.
|
228
|
+
*nokogiri*: for parsing and manipulating the document xml files.
|
211
229
|
|
212
230
|
|
213
231
|
<hr/>
|
data/lib/odf-report.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'zip/zipfilesystem'
|
3
3
|
require 'fileutils'
|
4
|
-
require
|
5
|
-
|
6
|
-
require File.expand_path('../odf-report/
|
7
|
-
require File.expand_path('../odf-report/
|
8
|
-
require File.expand_path('../odf-report/
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
require File.expand_path('../odf-report/images', __FILE__)
|
7
|
+
require File.expand_path('../odf-report/file_ops', __FILE__)
|
8
|
+
require File.expand_path('../odf-report/hash_gsub', __FILE__)
|
9
|
+
require File.expand_path('../odf-report/nested', __FILE__)
|
10
|
+
require File.expand_path('../odf-report/section', __FILE__)
|
11
|
+
require File.expand_path('../odf-report/table', __FILE__)
|
12
|
+
require File.expand_path('../odf-report/report', __FILE__)
|
data/lib/odf-report/file_ops.rb
CHANGED
@@ -2,6 +2,19 @@ module ODFReport
|
|
2
2
|
|
3
3
|
module FileOps
|
4
4
|
|
5
|
+
def create_new_file(dest)
|
6
|
+
|
7
|
+
if dest
|
8
|
+
FileUtils.cp(@template, dest)
|
9
|
+
new_file = dest
|
10
|
+
else
|
11
|
+
FileUtils.cp(@template, @tmp_dir)
|
12
|
+
new_file = "#{@tmp_dir}/#{File.basename(@template)}"
|
13
|
+
end
|
14
|
+
|
15
|
+
return new_file
|
16
|
+
end
|
17
|
+
|
5
18
|
def random_filename(opts={})
|
6
19
|
opts = {:chars => ('0'..'9').to_a + ('A'..'F').to_a + ('a'..'f').to_a,
|
7
20
|
:length => 24, :prefix => '', :suffix => '',
|
data/lib/odf-report/hash_gsub.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
module ODFReport
|
2
|
+
|
3
|
+
module Images
|
4
|
+
|
5
|
+
def find_image_name_matches(content)
|
6
|
+
|
7
|
+
@images.each_pair do |image_name, path|
|
8
|
+
#Search for the image placeholder path
|
9
|
+
image_rgx = Regexp.new("draw:name=\"#{image_name}\".*?>.*<draw:image.*?xlink:href=\"([^\s]*)\" .*?\/>.*</draw:frame>", Regexp::MULTILINE)
|
10
|
+
content_match = content.match(image_rgx)
|
11
|
+
|
12
|
+
if content_match
|
13
|
+
placeholder_path = content_match[1]
|
14
|
+
@image_names_replacements[path] = File.basename(placeholder_path)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def replace_images(new_file)
|
21
|
+
|
22
|
+
unless @images.empty?
|
23
|
+
image_dir_name = "Pictures"
|
24
|
+
FileUtils.mkdir(File.join("#{@tmp_dir}", image_dir_name))
|
25
|
+
@image_names_replacements.each_pair do |path, template_image|
|
26
|
+
template_image_path = File.join(image_dir_name, template_image)
|
27
|
+
update_file_from_zip(new_file, template_image_path) do |content|
|
28
|
+
content.replace File.read(path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ODFReport
|
2
|
+
|
3
|
+
module Nested
|
4
|
+
|
5
|
+
def replace_values!(new_section, data_item)
|
6
|
+
node_hash_gsub!(new_section, get_fields_with_values(data_item))
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_fields_with_values(data_item)
|
10
|
+
|
11
|
+
fields_with_values = {}
|
12
|
+
@fields.each do |field_name, block1|
|
13
|
+
fields_with_values[field_name] = block1.call(data_item) || ''
|
14
|
+
end
|
15
|
+
|
16
|
+
fields_with_values
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_collection_from_item(item, collection_field)
|
20
|
+
|
21
|
+
if collection_field.is_a?(Array)
|
22
|
+
tmp = item.dup
|
23
|
+
collection_field.each do |f|
|
24
|
+
if f.is_a?(Hash)
|
25
|
+
tmp = tmp.send(f.keys[0], f.values[0])
|
26
|
+
else
|
27
|
+
tmp = tmp.send(f)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
collection = tmp
|
31
|
+
elsif collection_field.is_a?(Hash)
|
32
|
+
collection = item.send(collection_field.keys[0], collection_field.values[0])
|
33
|
+
else
|
34
|
+
collection = item.send(collection_field)
|
35
|
+
end
|
36
|
+
|
37
|
+
return collection
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/odf-report/report.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module ODFReport
|
2
2
|
|
3
3
|
class Report
|
4
|
-
include HashGsub, FileOps
|
4
|
+
include HashGsub, FileOps, Images
|
5
5
|
|
6
6
|
attr_accessor :values, :tables, :images, :sections
|
7
7
|
|
@@ -14,35 +14,31 @@ class Report
|
|
14
14
|
@image_names_replacements = {}
|
15
15
|
@sections = []
|
16
16
|
|
17
|
-
@tmp_dir = Dir.tmpdir
|
17
|
+
@tmp_dir = File.join(Dir.tmpdir, random_filename(:prefix=>'odt_'))
|
18
18
|
Dir.mkdir(@tmp_dir) unless File.exists? @tmp_dir
|
19
19
|
|
20
20
|
yield(self)
|
21
21
|
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
|
26
|
-
@sections << sec
|
27
|
-
|
28
|
-
yield(sec)
|
29
|
-
|
30
|
-
sec.populate(collection)
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def add_field(field_tag, value)
|
35
|
-
@values[field_tag] = value || ''
|
24
|
+
def add_field(field_tag, value='')
|
25
|
+
@values[field_tag] = value
|
36
26
|
end
|
37
27
|
|
38
28
|
def add_table(table_name, collection, opts={}, &block)
|
39
|
-
opts
|
29
|
+
opts.merge!(:name => table_name, :collection => collection)
|
40
30
|
tab = Table.new(opts)
|
41
|
-
yield(tab)
|
42
31
|
@tables << tab
|
43
32
|
|
44
|
-
tab
|
33
|
+
yield(tab)
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_section(section_name, collection, opts={}, &block)
|
37
|
+
opts.merge!(:name => section_name, :collection => collection)
|
38
|
+
sec = Section.new(opts)
|
39
|
+
@sections << sec
|
45
40
|
|
41
|
+
yield(sec)
|
46
42
|
end
|
47
43
|
|
48
44
|
def add_image(name, path)
|
@@ -51,41 +47,27 @@ class Report
|
|
51
47
|
|
52
48
|
def generate(dest = nil)
|
53
49
|
|
54
|
-
|
50
|
+
new_file = create_new_file(dest)
|
55
51
|
|
56
|
-
|
57
|
-
new_file = dest
|
52
|
+
%w(content.xml styles.xml).each do |content_file|
|
58
53
|
|
59
|
-
|
54
|
+
update_file_from_zip(new_file, content_file) do |txt|
|
60
55
|
|
61
|
-
|
62
|
-
new_file = "#{@tmp_dir}/#{File.basename(@template)}"
|
56
|
+
parse_document(txt) do |doc|
|
63
57
|
|
64
|
-
|
58
|
+
replace_fields!(doc)
|
59
|
+
replace_sections!(doc)
|
60
|
+
replace_tables!(doc)
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
update_file_from_zip(new_file, content_file) do |txt|
|
62
|
+
end
|
69
63
|
|
70
|
-
|
71
|
-
replace_tables!(txt)
|
64
|
+
#TO_DO: make image use Nokogiri
|
72
65
|
find_image_name_matches(txt)
|
73
|
-
replace_sections!(txt)
|
74
|
-
|
75
66
|
end
|
76
67
|
|
77
68
|
end
|
78
69
|
|
79
|
-
|
80
|
-
image_dir_name = "Pictures"
|
81
|
-
FileUtils.mkdir(File.join("#{@tmp_dir}", image_dir_name))
|
82
|
-
@image_names_replacements.each_pair do |path, template_image|
|
83
|
-
template_image_path = File.join(image_dir_name, template_image)
|
84
|
-
update_file_from_zip(new_file, template_image_path) do |content|
|
85
|
-
content.replace File.read(path)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
70
|
+
replace_images(new_file)
|
89
71
|
|
90
72
|
new_file
|
91
73
|
|
@@ -93,37 +75,28 @@ class Report
|
|
93
75
|
|
94
76
|
private
|
95
77
|
|
78
|
+
def parse_document(txt)
|
79
|
+
doc = Nokogiri::XML(txt)
|
80
|
+
yield doc
|
81
|
+
txt.replace(doc.to_s)
|
82
|
+
end
|
83
|
+
|
96
84
|
def replace_fields!(content)
|
97
|
-
|
85
|
+
node_hash_gsub!(content, @values)
|
98
86
|
end
|
99
87
|
|
100
88
|
def replace_tables!(content)
|
101
|
-
|
102
89
|
@tables.each do |table|
|
103
90
|
table.replace!(content)
|
104
91
|
end
|
105
|
-
|
106
92
|
end
|
107
93
|
|
108
94
|
def replace_sections!(content)
|
109
|
-
|
110
95
|
@sections.each do |section|
|
111
96
|
section.replace!(content)
|
112
97
|
end
|
113
|
-
|
114
98
|
end
|
115
99
|
|
116
|
-
def find_image_name_matches(content)
|
117
|
-
@images.each_pair do |image_name, path|
|
118
|
-
#Search for the image placeholder path
|
119
|
-
image_rgx = Regexp.new("draw:name=\"#{image_name}\".*?><draw:image.*?xlink:href=\"([^\s]*)\" .*?/></draw:frame>")
|
120
|
-
content_match = content.match(image_rgx)
|
121
|
-
if content_match
|
122
|
-
placeholder_path = content_match[1]
|
123
|
-
@image_names_replacements[path] = File.basename(placeholder_path)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
100
|
end
|
128
101
|
|
129
102
|
end
|
data/lib/odf-report/section.rb
CHANGED
@@ -1,113 +1,93 @@
|
|
1
1
|
module ODFReport
|
2
2
|
|
3
|
-
class Section
|
4
|
-
|
3
|
+
class Section
|
4
|
+
include HashGsub, Nested
|
5
5
|
|
6
|
-
|
6
|
+
attr_accessor :fields, :tables, :data, :name, :collection_field, :parent
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
def initialize(opts)
|
9
|
+
@name = opts[:name]
|
10
|
+
@collection_field = opts[:collection_field]
|
11
|
+
@collection = opts[:collection]
|
12
|
+
@parent = opts[:parent]
|
10
13
|
|
11
|
-
|
12
|
-
@data = []
|
13
|
-
@tables = []
|
14
|
-
end
|
14
|
+
@fields = {}
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
@fields[name] = lambda { |item| item.send(field)}
|
19
|
-
else
|
20
|
-
@fields[name] = block
|
16
|
+
@tables = []
|
17
|
+
@sections = []
|
21
18
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def add_table(table_name, collection_field, opts={}, &block)
|
25
|
-
opts.merge!(:name => table_name, :collection_field => collection_field)
|
26
|
-
tab = Table.new(opts)
|
27
|
-
yield(tab)
|
28
|
-
@tables << tab
|
29
|
-
|
30
|
-
end
|
31
19
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
20
|
+
def add_field(name, field=nil, &block)
|
21
|
+
if field
|
22
|
+
@fields[name] = lambda { |item| item.send(field)}
|
23
|
+
elsif block_given?
|
24
|
+
@fields[name] = block
|
25
|
+
else
|
26
|
+
@fields[name] = lambda { |item| item.send(name)}
|
38
27
|
end
|
28
|
+
end
|
39
29
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
30
|
+
def add_table(table_name, collection_field, opts={}, &block)
|
31
|
+
opts.merge!(:name => table_name, :collection_field => collection_field, :parent => self)
|
32
|
+
tab = Table.new(opts)
|
33
|
+
@tables << tab
|
45
34
|
|
46
|
-
|
35
|
+
yield(tab)
|
47
36
|
end
|
48
37
|
|
49
|
-
|
38
|
+
def add_section(section_name, collection_field, opts={}, &block)
|
39
|
+
opts.merge!(:name => section_name, :collection_field => collection_field, :parent => self)
|
40
|
+
sec = Section.new(opts)
|
41
|
+
@sections << sec
|
50
42
|
|
51
|
-
|
43
|
+
yield(sec)
|
44
|
+
end
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
def populate!(row)
|
47
|
+
@collection = get_collection_from_item(row, @collection_field) if row
|
48
|
+
end
|
56
49
|
|
57
|
-
|
58
|
-
section_full = section_match[0]
|
59
|
-
section_content = section_match[2]
|
50
|
+
def replace!(doc, row = nil)
|
60
51
|
|
61
|
-
|
62
|
-
content.gsub!(section_full, "[SECTION_#{@name}]")
|
52
|
+
return unless section = find_section_node(doc)
|
63
53
|
|
64
|
-
|
54
|
+
template = section.dup
|
65
55
|
|
66
|
-
|
67
|
-
@data.each do |_values|
|
56
|
+
populate!(row)
|
68
57
|
|
69
|
-
|
70
|
-
|
71
|
-
tmp_row = section_content.dup
|
58
|
+
@collection.each do |data_item|
|
59
|
+
new_section = template.dup
|
72
60
|
|
73
|
-
|
74
|
-
hash_gsub!(tmp_row, _values)
|
61
|
+
replace_values!(new_section, data_item)
|
75
62
|
|
76
63
|
@tables.each do |t|
|
77
|
-
t.replace!(
|
64
|
+
t.replace!(new_section, data_item)
|
65
|
+
end
|
66
|
+
|
67
|
+
@sections.each do |s|
|
68
|
+
s.replace!(new_section, data_item)
|
78
69
|
end
|
79
70
|
|
80
|
-
|
71
|
+
section.before(new_section)
|
72
|
+
|
81
73
|
end
|
82
74
|
|
83
|
-
|
84
|
-
content.gsub!("[SECTION_#{@name}]", new_content)
|
75
|
+
section.remove
|
85
76
|
|
86
|
-
end #
|
77
|
+
end # replace_section
|
87
78
|
|
88
|
-
|
79
|
+
private
|
89
80
|
|
90
|
-
|
81
|
+
def find_section_node(doc)
|
91
82
|
|
92
|
-
|
83
|
+
prefix = @parent ? "" : "//"
|
84
|
+
|
85
|
+
sections = doc.xpath("#{prefix}text:section[@text:name='#{@name}']")
|
86
|
+
|
87
|
+
sections.empty? ? nil : sections.first
|
93
88
|
|
94
|
-
if collection_field.is_a?(Array)
|
95
|
-
tmp = item.dup
|
96
|
-
collection_field.each do |f|
|
97
|
-
if f.is_a?(Hash)
|
98
|
-
tmp = tmp.send(f.keys[0], f.values[0])
|
99
|
-
else
|
100
|
-
tmp = tmp.send(f)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
collection = tmp
|
104
|
-
else
|
105
|
-
collection = item.send(collection_field)
|
106
89
|
end
|
107
90
|
|
108
|
-
return collection
|
109
91
|
end
|
110
92
|
|
111
|
-
end
|
112
|
-
|
113
93
|
end
|
data/lib/odf-report/table.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
module ODFReport
|
2
2
|
|
3
3
|
class Table
|
4
|
-
include HashGsub
|
4
|
+
include HashGsub, Nested
|
5
5
|
|
6
|
-
attr_accessor :fields, :rows, :name, :collection_field, :data, :header
|
6
|
+
attr_accessor :fields, :rows, :name, :collection_field, :data, :header, :parent
|
7
7
|
|
8
8
|
def initialize(opts)
|
9
9
|
@name = opts[:name]
|
10
10
|
@collection_field = opts[:collection_field]
|
11
11
|
@collection = opts[:collection]
|
12
|
-
@
|
12
|
+
@parent = opts[:parent]
|
13
13
|
|
14
14
|
@fields = {}
|
15
|
-
|
16
|
-
@
|
15
|
+
|
16
|
+
@template_rows = []
|
17
|
+
@header = opts[:header] || false
|
17
18
|
end
|
18
19
|
|
19
20
|
def add_column(name, field=nil, &block)
|
@@ -26,104 +27,68 @@ class Table
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
|
31
|
-
collection.each do |item|
|
32
|
-
row = {}
|
33
|
-
@fields.each do |field_name, block1|
|
34
|
-
row[field_name] = block1.call(item) || ''
|
35
|
-
end
|
36
|
-
ret << row
|
37
|
-
end
|
38
|
-
ret
|
39
|
-
end
|
40
|
-
|
41
|
-
def populate(collection)
|
42
|
-
@data = values(collection)
|
30
|
+
def populate!(row)
|
31
|
+
@collection = get_collection_from_item(row, @collection_field) if row
|
43
32
|
end
|
44
33
|
|
45
|
-
def replace!(
|
46
|
-
@data = rows if rows
|
47
|
-
|
48
|
-
# search for the table inside the content
|
49
|
-
table_rgx = Regexp.new("(<table:table table:name=\"#{@name}.*?>.*?<\/table:table>)", "m")
|
50
|
-
table_match = content.match(table_rgx)
|
51
|
-
|
52
|
-
if table_match
|
53
|
-
table = table_match[0]
|
34
|
+
def replace!(doc, row = nil)
|
54
35
|
|
55
|
-
|
56
|
-
content.gsub!(table, "[TABLE_#{@name}]")
|
36
|
+
return unless table = find_table_node(doc)
|
57
37
|
|
58
|
-
|
59
|
-
row_rgx = Regexp.new("(<table:table-row.*?<\/table:table-row>)", "m")
|
38
|
+
populate!(row)
|
60
39
|
|
61
|
-
|
62
|
-
# and scan returns all matches
|
63
|
-
row_match = table.scan(row_rgx)
|
40
|
+
@template_rows = table.xpath("table:table-row")
|
64
41
|
|
65
|
-
|
42
|
+
@collection.each do |data_item|
|
66
43
|
|
67
|
-
|
44
|
+
new_node = get_next_row
|
68
45
|
|
69
|
-
|
46
|
+
replace_values!(new_node, data_item)
|
70
47
|
|
71
|
-
|
72
|
-
@data.each do |_values|
|
48
|
+
table.add_child(new_node)
|
73
49
|
|
74
|
-
|
75
|
-
# from the original table
|
76
|
-
tmp_row = get_next_row.dup
|
77
|
-
|
78
|
-
# replace values in the model_row and stores in new_rows
|
79
|
-
hash_gsub!(tmp_row, _values)
|
80
|
-
|
81
|
-
new_rows << tmp_row
|
82
|
-
end
|
50
|
+
end
|
83
51
|
|
84
|
-
|
85
|
-
|
52
|
+
@template_rows.each_with_index do |r, i|
|
53
|
+
r.remove if (get_start_node..template_lenght) === i
|
54
|
+
end
|
86
55
|
|
87
|
-
|
56
|
+
end # replace
|
88
57
|
|
89
|
-
|
90
|
-
if @data.empty?
|
91
|
-
content.gsub!("[TABLE_#{@name}]", "")
|
92
|
-
else
|
93
|
-
content.gsub!("[TABLE_#{@name}]", table)
|
94
|
-
end
|
58
|
+
private
|
95
59
|
|
96
|
-
|
60
|
+
def get_next_row
|
61
|
+
@row_cursor = get_start_node unless defined?(@row_cursor)
|
97
62
|
|
98
|
-
|
63
|
+
ret = @template_rows[@row_cursor]
|
64
|
+
if @template_rows.size == @row_cursor + 1
|
65
|
+
@row_cursor = get_start_node
|
66
|
+
else
|
67
|
+
@row_cursor += 1
|
68
|
+
end
|
69
|
+
return ret.dup
|
70
|
+
end
|
99
71
|
|
100
|
-
|
72
|
+
def get_start_node
|
73
|
+
@header ? 1 : 0
|
74
|
+
end
|
101
75
|
|
102
|
-
def
|
76
|
+
def reset
|
77
|
+
@row_cursor = get_start_node
|
78
|
+
end
|
103
79
|
|
104
|
-
|
80
|
+
def template_lenght
|
81
|
+
@tl ||= @template_rows.size
|
82
|
+
end
|
105
83
|
|
106
|
-
|
107
|
-
@row_cursor = 0
|
84
|
+
def find_table_node(doc)
|
108
85
|
|
109
|
-
|
110
|
-
first = rows.delete_at(0)[0]
|
111
|
-
table.gsub!(first, "[ROW_#{@name}]")
|
86
|
+
prefix = @parent ? "" : "//"
|
112
87
|
|
113
|
-
|
114
|
-
table.gsub!(r[0], "")
|
115
|
-
end
|
88
|
+
tables = doc.xpath("#{prefix}table:table[@table:name='#{@name}']")
|
116
89
|
|
117
|
-
|
90
|
+
tables.empty? ? nil : tables.first
|
118
91
|
|
119
|
-
def get_next_row
|
120
|
-
ret = @rows[@row_cursor]
|
121
|
-
if @rows.size == @row_cursor + 1
|
122
|
-
@row_cursor = 0
|
123
|
-
else
|
124
|
-
@row_cursor += 1
|
125
|
-
end
|
126
|
-
return ret[0]
|
127
92
|
end
|
128
93
|
|
129
94
|
end
|
data/odf-report.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{odf-report}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.4.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Sandro Duarte"]
|
9
|
-
s.date = %q{2011-
|
9
|
+
s.date = %q{2011-09-23}
|
10
10
|
s.description = %q{Generates ODF files, given a template (.odt) and data, replacing tags}
|
11
11
|
s.email = %q{sandrods@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["lib/odf-report.rb", "README.textile"]
|
13
|
-
s.files = %w{lib/odf-report.rb odf-report.gemspec README.textile
|
13
|
+
s.files = %w{lib/odf-report.rb odf-report.gemspec README.textile Manifest lib/odf-report/report.rb lib/odf-report/table.rb lib/odf-report/section.rb lib/odf-report/file_ops.rb lib/odf-report/hash_gsub.rb lib/odf-report/images.rb lib/odf-report/nested.rb }
|
14
14
|
s.has_rdoc = false
|
15
15
|
s.homepage = %q{}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Odf-report", "--main", "README.textile"]
|
@@ -24,10 +24,13 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
26
|
s.add_runtime_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
|
27
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0", ">= 1.5.0"])
|
27
28
|
else
|
28
29
|
s.add_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
|
30
|
+
s.add_dependency(%q<nokogiri>, [">= 0", ">= 1.5.0"])
|
29
31
|
end
|
30
32
|
else
|
31
33
|
s.add_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
|
34
|
+
s.add_dependency(%q<nokogiri>, [">= 0", ">= 1.5.0"])
|
32
35
|
end
|
33
36
|
end
|
metadata
CHANGED
@@ -1,97 +1,91 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: odf-report
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 3
|
8
|
-
- 3
|
9
|
-
version: 0.3.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Sandro Duarte
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-09-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rubyzip
|
22
|
-
|
23
|
-
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
segments:
|
33
|
-
- 0
|
34
|
-
- 9
|
35
|
-
- 4
|
16
|
+
requirement: &2152736240 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
- - ! '>='
|
23
|
+
- !ruby/object:Gem::Version
|
36
24
|
version: 0.9.4
|
37
25
|
type: :runtime
|
38
|
-
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: *2152736240
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: nokogiri
|
30
|
+
requirement: &2152735160 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 1.5.0
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: *2152735160
|
39
42
|
description: Generates ODF files, given a template (.odt) and data, replacing tags
|
40
43
|
email: sandrods@gmail.com
|
41
44
|
executables: []
|
42
|
-
|
43
45
|
extensions: []
|
44
|
-
|
45
|
-
extra_rdoc_files:
|
46
|
+
extra_rdoc_files:
|
46
47
|
- lib/odf-report.rb
|
47
48
|
- README.textile
|
48
|
-
files:
|
49
|
+
files:
|
49
50
|
- lib/odf-report.rb
|
50
51
|
- odf-report.gemspec
|
51
52
|
- README.textile
|
52
|
-
- test/test.odt
|
53
|
-
- test/test.rb
|
54
53
|
- Manifest
|
55
54
|
- lib/odf-report/report.rb
|
56
55
|
- lib/odf-report/table.rb
|
57
56
|
- lib/odf-report/section.rb
|
58
57
|
- lib/odf-report/file_ops.rb
|
59
58
|
- lib/odf-report/hash_gsub.rb
|
60
|
-
|
61
|
-
|
59
|
+
- lib/odf-report/images.rb
|
60
|
+
- lib/odf-report/nested.rb
|
61
|
+
homepage: ''
|
62
62
|
licenses: []
|
63
|
-
|
64
63
|
post_install_message:
|
65
|
-
rdoc_options:
|
64
|
+
rdoc_options:
|
66
65
|
- --line-numbers
|
67
66
|
- --inline-source
|
68
67
|
- --title
|
69
68
|
- Odf-report
|
70
69
|
- --main
|
71
70
|
- README.textile
|
72
|
-
require_paths:
|
71
|
+
require_paths:
|
73
72
|
- lib
|
74
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
requirements:
|
83
|
-
- -
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
|
86
|
-
- 1
|
87
|
-
- 2
|
88
|
-
version: "1.2"
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '1.2'
|
89
85
|
requirements: []
|
90
|
-
|
91
86
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.
|
87
|
+
rubygems_version: 1.8.10
|
93
88
|
signing_key:
|
94
89
|
specification_version: 2
|
95
90
|
summary: Generates ODF files, given a template (.odt) and data, replacing tags
|
96
91
|
test_files: []
|
97
|
-
|
data/test/test.odt
DELETED
Binary file
|
data/test/test.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
require '../lib/odf-report'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
|
-
col1 = []
|
5
|
-
(1..15).each do |i|
|
6
|
-
col1 << OpenStruct.new({:name=>"name #{i}", :id=>i, :address=>"this is address #{i}"})
|
7
|
-
end
|
8
|
-
|
9
|
-
|
10
|
-
col2 = []
|
11
|
-
col2 << OpenStruct.new({:name=>"josh harnet", :id=>"02", :address=>"testing <&> ", :phone=>99025668, :zip=>"90420-002"})
|
12
|
-
col2 << OpenStruct.new({:name=>"sandro duarte", :id=>"45", :address=>"address with &", :phone=>88774451, :zip=>"90490-002"})
|
13
|
-
col2 << OpenStruct.new({:name=>"ellen bicca", :id=>"77", :address=>"<address with escaped html>", :phone=>77025668, :zip=>"94420-002"})
|
14
|
-
col2 << OpenStruct.new({:name=>"luiz garcia", :id=>"88", :address=>"address with\nlinebreak", :phone=>27025668, :zip=>"94520-025"})
|
15
|
-
|
16
|
-
report = ODFReport::Report.new("test.odt") do |r|
|
17
|
-
|
18
|
-
r.add_field("HEADER_FIELD", "This field was in the HEADER")
|
19
|
-
|
20
|
-
r.add_field("TAG_01", "New tag")
|
21
|
-
r.add_field("TAG_02", "TAG-2 -> New tag")
|
22
|
-
|
23
|
-
r.add_table("TABLE_01", col1, :header=>true) do |t|
|
24
|
-
t.add_column(:field_01, :id)
|
25
|
-
t.add_column(:field_02, :name)
|
26
|
-
t.add_column(:field_03, :address)
|
27
|
-
end
|
28
|
-
|
29
|
-
r.add_table("TABLE_02", col2) do |t|
|
30
|
-
t.add_column(:field_04, :id)
|
31
|
-
t.add_column(:field_05, :name)
|
32
|
-
t.add_column(:field_06, :address)
|
33
|
-
t.add_column(:field_07, :phone)
|
34
|
-
t.add_column(:field_08, :zip)
|
35
|
-
end
|
36
|
-
|
37
|
-
r.add_image("graphics1", File.join(Dir.pwd, 'piriapolis.jpg'))
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
report.generate("result.odt")
|
42
|
-
|
43
|
-
class Item
|
44
|
-
attr_accessor :name, :sid, :children
|
45
|
-
def initialize(_name, _sid, _children=[])
|
46
|
-
@name=_name
|
47
|
-
@sid=_sid
|
48
|
-
@children=_children
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
items = []
|
53
|
-
items << Item.new("Dexter Morgan", '007', %w(sawyer juliet hurley locke jack freckles))
|
54
|
-
items << Item.new("Danny Crane", '302', %w(sidney sloane jack michael marshal))
|
55
|
-
items << Item.new("Coach Taylor", '220', %w(meredith christina izzie alex george))
|
56
|
-
|
57
|
-
report = ODFReport::Report.new("sections.odt") do |r|
|
58
|
-
|
59
|
-
r.add_field("TAG_01", "New tag")
|
60
|
-
r.add_field("TAG_02", "TAG-2 -> New tag")
|
61
|
-
|
62
|
-
r.add_section("SECTION_01", items) do |s|
|
63
|
-
|
64
|
-
s.add_field('NAME') do |i|
|
65
|
-
i.name
|
66
|
-
end
|
67
|
-
|
68
|
-
s.add_field('SID', :sid)
|
69
|
-
|
70
|
-
s.add_table('TABLE_S1', :children, :header=>true) do |t|
|
71
|
-
t.add_column('NAME1') { |item| "-> #{item}" }
|
72
|
-
t.add_column('INV') { |item| item.to_s.reverse.upcase }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
report.generate("section_result.odt")
|