odf-report 0.3.3 → 0.4.0
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/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")
|