flexy-odf-report 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest ADDED
@@ -0,0 +1,12 @@
1
+ lib/odf-report.rb
2
+ lib/odf-report/report.rb
3
+ lib/odf-report/table.rb
4
+ lib/odf-report/section.rb
5
+ lib/odf-report/file_ops.rb
6
+ lib/odf-report/hash_gsub.rb
7
+ odf-report.gemspec
8
+ README.textile
9
+ test/test.odt
10
+ test/sections.odt
11
+ test/test.rb
12
+ Manifest
data/README.textile ADDED
@@ -0,0 +1,219 @@
1
+ h1. ODF-REPORT
2
+
3
+ Gem for generating .odt files by making strings, images, tables and sections replacements in a previously created .odt file.
4
+
5
+
6
+ h2. INSTALL
7
+
8
+ (sudo) gem install odf-report
9
+
10
+
11
+ h2. USAGE
12
+
13
+ h3. Step 1 -- the template
14
+
15
+ First of all, you need to create a .odt file to serve as a template
16
+
17
+ Templates are normal .odt files with placeholders for Substitutions
18
+
19
+ There are now *four* kinds of substitutions available: *fields*, *tables*, *images* and *sections*.
20
+
21
+ h3. Fields placeholders
22
+
23
+ It's just an upcase sentence, surrounded by brackets. It will be replaced for wathever value you supply.
24
+
25
+ In the folowing example:
26
+
27
+ <pre>
28
+ report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
29
+
30
+ r.add_field :user_name, @user.name
31
+ r.add_field :address, "My new address"
32
+
33
+ end
34
+ </pre>
35
+
36
+ All occurences of @[USER_NAME]@ found in the file will be replaced by the value of @@user.name@ whereas all @[ADDRESS]@ 'es will contains @My new address@
37
+
38
+ It's as simple as that.
39
+
40
+
41
+ h3. Table placeholders
42
+
43
+ To use table placeholders, you should create a Table in your document and give it a name. In OpenOffice, it's just a matter of right-clicking the table you just created, choose _Table Properties..._ and type a name in the Name field.
44
+
45
+ If you inform @:header=>true@, the first row will be treated as a *header* and left untouched. The remaining rows will be used as the template for the table. If you have more than one template row, they will be cycled. This is usefull for making zebra tables.
46
+
47
+ As with Field placeholders, just insert a @[FIELD_NAME]@ in each cell and let the magic takes place.
48
+
49
+ Taking the folowing example:
50
+
51
+ <pre>
52
+ report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
53
+
54
+ r.add_field "USER_NAME", @user.nome
55
+ r.add_field "ADDRESS", @user.address
56
+
57
+ r.add_table("TABLE_1", @list_of_itens, :header=>true) do |t|
58
+ t.add_column(:item_id, :id)
59
+ t.add_column(:description) do { |item| "==> #{item.description}" }
60
+ end
61
+
62
+ end
63
+ </pre>
64
+
65
+ and considering you have a table like this in your template
66
+
67
+ <pre>
68
+ ---------------------------------
69
+ | [ITEM_ID] | [DESCRIPTION] |
70
+ ---------------------------------
71
+
72
+ * this is my lame attempt to draw a table.
73
+ you don't suppose to type this.
74
+ you have to use an actual table.
75
+ i don't know... just thought I'd mention it ;-)
76
+ </pre>
77
+
78
+ and a collection @list_of_itens, it will be created one row for each item in the collection, and the replacement will take place accordingly.
79
+
80
+ Any format applied to the fields in the template will be preserved.
81
+
82
+
83
+ h3. Images
84
+
85
+ You must put a mock image in your odt template and give it a name. That name will be used to replace the mock image for the actual image.
86
+ You can also assign any properties you want to the mock image and they will be kept once the image is replaced.
87
+
88
+ An image replace would look like this:
89
+
90
+ <pre>
91
+ report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
92
+
93
+ r.add_image :graphics1, "/path/to/the/image.jpg"
94
+
95
+ end
96
+ </pre>
97
+
98
+
99
+ h3. Sections (NEW!)
100
+
101
+ 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
+
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, as long as you pass the appropriate data structure.
104
+
105
+ Let's see an example:
106
+
107
+ <pre>
108
+
109
+ @invoices = Invoice.find(:all)
110
+
111
+ report = ODFReport::Report.new("reports/invoice.odt") do |r|
112
+
113
+ r.add_field(:title, "INVOICES REPORT")
114
+ r.add_field(:date, Date.today)
115
+
116
+ r.add_section("SC_INVOICE", @invoices) do |s|
117
+
118
+ s.add_field(:number) { |invoice| invoice.number.to_s.rjust(5, '0') }
119
+ s.add_field(:name, :customer_name)
120
+ s.add_field(:address, :customer_address)
121
+
122
+ s.add_table("TB_ITEMS", :items, :header => true) do |t|
123
+ t.add_column(:id)
124
+ t.add_column(:product) {|item| item.product.name }
125
+ t.add_column(:value, :product_value)
126
+ end
127
+
128
+ s.add_field(:total) do |invoice|
129
+ if invoice.status == 'CLOSED'
130
+ invoice.total
131
+ else
132
+ invoice.items.sum('product_value')}
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+ </pre>
140
+
141
+ Note that when you add a Table to a Section, you don't pass the collection itself, but the attribute of the item of that section that's gonna return the collection for that particular Table. Sounds complicated, huh? But once you get it, it's quite straightforward.
142
+
143
+ In the above example, @s.add_table("TB_ITEMS", :items, :header => true) do |t|@, the @:items@ thing refers to a @invoice.items@. Easy, right?
144
+
145
+ <hr/><br/>
146
+
147
+ h3. Step 2 -- generating the document
148
+
149
+ It's fairly simple to generate the document. You can use this inside a Rails application or in a standalone script.
150
+
151
+ h4. Generating a document in a Rails application
152
+
153
+ In a controller, you can have a code like this:
154
+
155
+ <pre>
156
+ def print
157
+
158
+ @ticket = Ticket.find(params[:id])
159
+
160
+ report = ODFReport::Report.new("#{RAILS_ROOT}/app/reports/ticket.odt") do |r|
161
+
162
+ r.add_field(:id, @ticket.id.to_s)
163
+ r.add_field(:created_by, @ticket.created_by)
164
+ r.add_field(:created_at, @ticket.created_at.strftime("%d/%m/%Y - %H:%M"))
165
+ r.add_field(:type, @ticket.type.name)
166
+ r.add_field(:status, @ticket.status_text)
167
+ r.add_field(:date, Time.now.strftime("%d/%m/%Y - %H:%M"))
168
+ r.add_field(:solution, (@ticket.solution || ''))
169
+
170
+ r.add_table("OPERATORS", @ticket.operators) do |t|
171
+ t.add_column(:operator_name) { |op| "#{op.name} (#{op.department.short_name})" }
172
+ end
173
+
174
+ r.add_table("FIELDS", @ticket.fields) do |t|
175
+ t.add_column(:field_name, :name)
176
+ t.add_column(:field_value) { |field| field.text_value || "Empty" }
177
+ end
178
+
179
+ end
180
+
181
+ report_file_name = report.generate
182
+
183
+ send_file(report_file_name)
184
+
185
+ end
186
+ </pre>
187
+
188
+ The @generate@ method will, er... generate the document in a temp dir and returns the full path of the generated file, so you can send it back to the user.
189
+
190
+ _That's all I have to say about that._
191
+
192
+ h4. Generating a document in a standalone script
193
+
194
+ It's just the same as in a Rails app, but you can inform the path where the file will be generated instead of using a temp dir.
195
+
196
+ <pre>
197
+ report = ODFReport::Report.new("ticket.odt") do |r|
198
+
199
+ ... populates the report ...
200
+
201
+ end
202
+
203
+ report.generate("./documents/")
204
+ </pre>
205
+
206
+ <hr/>
207
+
208
+ h3. REQUIREMENTS
209
+
210
+ *rubyzip*: for manipulating the contents of the odt file, since it's actually a zip file.
211
+
212
+
213
+ <hr/>
214
+
215
+ h3. THE FUTURE
216
+
217
+ Well, this is my first attempt. This gem was extracted from an actual project we developed internally, to fulfill our specific needs.
218
+
219
+ That said, I would really appreciate any input you can come up with. Critics, suggestions, bug reports are welcome and will be thoroughly examined.
data/lib/odf-report.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'zip/zipfilesystem'
3
+ require 'fileutils'
4
+ require File.expand_path('../odf-report/file_ops',__FILE__)
5
+ require File.expand_path('../odf-report/hash_gsub',__FILE__)
6
+ require File.expand_path('../odf-report/section',__FILE__)
7
+ require File.expand_path('../odf-report/table',__FILE__)
8
+ require File.expand_path('../odf-report/report',__FILE__)
@@ -0,0 +1,57 @@
1
+ module ODFReport
2
+
3
+ module FileOps
4
+
5
+ def random_filename(opts={})
6
+ opts = {:chars => ('0'..'9').to_a + ('A'..'F').to_a + ('a'..'f').to_a,
7
+ :length => 24, :prefix => '', :suffix => '',
8
+ :verify => true, :attempts => 10}.merge(opts)
9
+ opts[:attempts].times do
10
+ filename = ''
11
+ opts[:length].times { filename << opts[:chars][rand(opts[:chars].size)] }
12
+ filename = opts[:prefix] + filename + opts[:suffix]
13
+ return filename unless opts[:verify] && File.exists?(filename)
14
+ end
15
+ nil
16
+ end
17
+
18
+ def add_files_to_dir(files, dir)
19
+ FileUtils.mkdir(dir)
20
+ files.each do |path|
21
+ FileUtils.cp(path, File.join(dir, File.basename(path)))
22
+ end
23
+ end
24
+
25
+ def add_dir_to_zip(zip_file, dir, entry)
26
+ Zip::ZipFile.open(zip_file, true) do |z|
27
+ Dir["#{dir}/**/*"].each { |f| z.add("#{entry}/#{File.basename(f)}", f) }
28
+ end
29
+ end
30
+
31
+ def update_file_from_zip(zip_file, content_file, &block)
32
+
33
+ Zip::ZipFile.open(zip_file) do |z|
34
+ cont = "#{@tmp_dir}/#{content_file}"
35
+
36
+ z.extract(content_file, cont)
37
+
38
+ txt = ''
39
+
40
+ File.open(cont, "r") do |f|
41
+ txt = f.read
42
+ end
43
+
44
+ yield(txt)
45
+
46
+ File.open(cont, "w") do |f|
47
+ f.write(txt)
48
+ end
49
+
50
+ z.replace(content_file, cont)
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,27 @@
1
+ module ODFReport
2
+
3
+ module HashGsub
4
+
5
+ def hash_gsub!(_text, hash_of_values)
6
+ hash_of_values.each do |key, val|
7
+ txt = html_escape(val)
8
+ txt = odf_linebreak(txt)
9
+ _text.gsub!("[#{key.to_s.upcase}]", txt)
10
+ end
11
+ end
12
+
13
+ HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
14
+
15
+ def html_escape(s)
16
+ return "" unless s
17
+ s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
18
+ end
19
+
20
+ def odf_linebreak(s)
21
+ return "" unless s
22
+ s.to_s.gsub("\n", "<text:line-break/>")
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,129 @@
1
+ module ODFReport
2
+
3
+ class Report
4
+ include HashGsub, FileOps
5
+
6
+ attr_accessor :values, :tables, :images, :sections
7
+
8
+ def initialize(template_name, &block)
9
+ @template = template_name
10
+
11
+ @values = {}
12
+ @tables = []
13
+ @images = {}
14
+ @image_names_replacements = {}
15
+ @sections = []
16
+
17
+ @tmp_dir = Dir.tmpdir + "/" + random_filename(:prefix=>'odt_')
18
+ Dir.mkdir(@tmp_dir) unless File.exists? @tmp_dir
19
+
20
+ yield(self)
21
+
22
+ end
23
+
24
+ def add_section(section_name, collection, &block)
25
+ sec = Section.new(section_name)
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 || ''
36
+ end
37
+
38
+ def add_table(table_name, collection, opts={}, &block)
39
+ opts[:name] = table_name
40
+ tab = Table.new(opts)
41
+ yield(tab)
42
+ @tables << tab
43
+
44
+ tab.populate(collection)
45
+
46
+ end
47
+
48
+ def add_image(name, path)
49
+ @images[name] = path
50
+ end
51
+
52
+ def generate(dest = nil)
53
+
54
+ if dest
55
+
56
+ FileUtils.cp(@template, dest)
57
+ new_file = dest
58
+
59
+ else
60
+
61
+ FileUtils.cp(@template, @tmp_dir)
62
+ new_file = "#{@tmp_dir}/#{File.basename(@template)}"
63
+
64
+ end
65
+
66
+ %w(content.xml styles.xml).each do |content_file|
67
+
68
+ update_file_from_zip(new_file, content_file) do |txt|
69
+
70
+ replace_fields!(txt)
71
+ replace_tables!(txt)
72
+ find_image_name_matches(txt)
73
+ replace_sections!(txt)
74
+
75
+ end
76
+
77
+ end
78
+
79
+ unless @images.empty?
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
89
+
90
+ new_file
91
+
92
+ end
93
+
94
+ private
95
+
96
+ def replace_fields!(content)
97
+ hash_gsub!(content, @values)
98
+ end
99
+
100
+ def replace_tables!(content)
101
+
102
+ @tables.each do |table|
103
+ table.replace!(content)
104
+ end
105
+
106
+ end
107
+
108
+ def replace_sections!(content)
109
+
110
+ @sections.each do |section|
111
+ section.replace!(content)
112
+ end
113
+
114
+ end
115
+
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
+ end
128
+
129
+ end
@@ -0,0 +1,113 @@
1
+ module ODFReport
2
+
3
+ class Section
4
+ include HashGsub
5
+
6
+ attr_accessor :fields, :tables, :data, :name
7
+
8
+ def initialize(name)
9
+ @name = name
10
+
11
+ @fields = {}
12
+ @data = []
13
+ @tables = []
14
+ end
15
+
16
+ def add_field(name, field=nil, &block)
17
+ if field
18
+ @fields[name] = lambda { |item| item.send(field)}
19
+ else
20
+ @fields[name] = block
21
+ 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
+
32
+ def populate(collection)
33
+
34
+ collection.each do |item|
35
+ row = {}
36
+ @fields.each do |field_name, block1|
37
+ row[field_name] = block1.call(item)
38
+ end
39
+
40
+ row[:tables] = {}
41
+ @tables.each do |table|
42
+ collection = get_collection_from_item(item, table.collection_field)
43
+ row[:tables][table.name] = table.values(collection)
44
+ end
45
+
46
+ @data << row
47
+ end
48
+
49
+ end
50
+
51
+ def replace!(content)
52
+
53
+ # search for the table inside the content
54
+ section_rgx = Regexp.new("(<text:section.*?text:name=\"#{@name}.*?>(.*?)<\/text:section>)", "m")
55
+ section_match = content.match(section_rgx)
56
+
57
+ if section_match
58
+ section_full = section_match[0]
59
+ section_content = section_match[2]
60
+
61
+ # extract the section from the content
62
+ content.gsub!(section_full, "[SECTION_#{@name}]")
63
+
64
+ new_content = ""
65
+
66
+ # for each record
67
+ @data.each do |_values|
68
+
69
+ # generates one new row (table-row), based in the model extracted
70
+ # from the original table
71
+ tmp_row = section_content.dup
72
+
73
+ # replace values in the section_content and stores in new_content
74
+ hash_gsub!(tmp_row, _values)
75
+
76
+ @tables.each do |t|
77
+ t.replace!(tmp_row, _values[:tables][t.name])
78
+ end
79
+
80
+ new_content << tmp_row
81
+ end
82
+
83
+ # replace back the table into content
84
+ content.gsub!("[SECTION_#{@name}]", new_content)
85
+
86
+ end # if table match
87
+
88
+ end # replace_section
89
+
90
+ private
91
+
92
+ def get_collection_from_item(item, collection_field)
93
+
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
+ end
107
+
108
+ return collection
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,144 @@
1
+ module ODFReport
2
+
3
+ class Table
4
+ include HashGsub
5
+
6
+ attr_accessor :fields, :rows, :name, :collection_field, :data, :header
7
+
8
+ def initialize(opts)
9
+ @name = opts[:name]
10
+ @collection_field = opts[:collection_field]
11
+ @collection = opts[:collection]
12
+ @header = opts[:header] || false
13
+
14
+ @fields = {}
15
+ @rows = []
16
+ @data = []
17
+ end
18
+
19
+ #
20
+ # Old version
21
+ #
22
+ def add_column(name, field=nil, &block)
23
+ add_column_if(true, name, field, &block)
24
+ end
25
+
26
+ #
27
+ # New version
28
+ #
29
+ def add_column_if(condition, name, field=nil, &block)
30
+ if condition
31
+ # Only render the column if condition holds true...
32
+ if field
33
+ @fields[name] = lambda { |item| item.send(field)}
34
+ elsif block_given?
35
+ @fields[name] = block
36
+ else
37
+ @fields[name] = lambda { |item| item.send(name)}
38
+ end
39
+ end
40
+ end
41
+
42
+ def values(collection)
43
+ ret = []
44
+ collection.each do |item|
45
+ row = {}
46
+ @fields.each do |field_name, block1|
47
+ row[field_name] = block1.call(item) || ''
48
+ end
49
+ ret << row
50
+ end
51
+ ret
52
+ end
53
+
54
+ def populate(collection)
55
+ @data = values(collection)
56
+ end
57
+
58
+ def replace!(content, rows = nil)
59
+ @data = rows if rows
60
+
61
+ # search for the table inside the content
62
+ table_rgx = Regexp.new("(<table:table table:name=\"#{@name}.*?>.*?<\/table:table>)", "m")
63
+ table_match = content.match(table_rgx)
64
+
65
+ if table_match
66
+ table = table_match[0]
67
+
68
+ # extract the table from the content
69
+ content.gsub!(table, "[TABLE_#{@name}]")
70
+
71
+ # search for the table:row's
72
+ row_rgx = Regexp.new("(<table:table-row.*?<\/table:table-row>)", "m")
73
+
74
+ # use scan (instead of match) as the table can have more than one table-row (header and data)
75
+ # and scan returns all matches
76
+ row_match = table.scan(row_rgx)
77
+
78
+ unless row_match.empty?
79
+
80
+ replace_rows!(table, row_match)
81
+
82
+ new_rows = ""
83
+
84
+ # for each record
85
+ @data.each do |_values|
86
+
87
+ # generates one new row (table-row), based in the model extracted
88
+ # from the original table
89
+ tmp_row = get_next_row.dup
90
+
91
+ # replace values in the model_row and stores in new_rows
92
+ hash_gsub!(tmp_row, _values)
93
+
94
+ new_rows << tmp_row
95
+ end
96
+
97
+ # replace back the lines into the table
98
+ table.gsub!("[ROW_#{@name}]", new_rows)
99
+
100
+ end # unless row_match.empty?
101
+
102
+ # replace back the table into content
103
+ if @data.empty?
104
+ content.gsub!("[TABLE_#{@name}]", "")
105
+ else
106
+ content.gsub!("[TABLE_#{@name}]", table)
107
+ end
108
+
109
+ end # if table match
110
+
111
+ end # replace
112
+
113
+ private
114
+
115
+ def replace_rows!(table, rows)
116
+
117
+ rows.delete_at(0) if @header # ignore the header
118
+
119
+ @rows = rows.dup
120
+ @row_cursor = 0
121
+
122
+ # extract the rows from the table
123
+ first = rows.delete_at(0)[0]
124
+ table.gsub!(first, "[ROW_#{@name}]")
125
+
126
+ rows.each do |r|
127
+ table.gsub!(r[0], "")
128
+ end
129
+
130
+ end
131
+
132
+ def get_next_row
133
+ ret = @rows[@row_cursor]
134
+ if @rows.size == @row_cursor + 1
135
+ @row_cursor = 0
136
+ else
137
+ @row_cursor += 1
138
+ end
139
+ return ret[0]
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{flexy-odf-report}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Sandro Duarte", "Mark von Zeschau"]
9
+ s.date = %q{2011-06-07}
10
+ s.description = %q{Generates ODF files, given a template (.odt) and data, replacing tags. Same as the original odf-report gem but adds some more features.}
11
+ s.email = %q{sandrods@gmail.com}
12
+ s.extra_rdoc_files = ["lib/odf-report.rb", "README.textile"]
13
+ s.files = %w{lib/odf-report.rb odf-report.gemspec README.textile test/test.odt test/test.rb 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 }
14
+ s.has_rdoc = false
15
+ s.homepage = %q{}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Odf-report", "--main", "README.textile"]
17
+ s.require_paths = ["lib"]
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Generates ODF files, given a template (.odt) and data, replacing tags. Same as the original odf-report gem but adds some more features.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
27
+ else
28
+ s.add_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
29
+ end
30
+ else
31
+ s.add_dependency(%q<rubyzip>, [">= 0", ">= 0.9.4"])
32
+ end
33
+ end
data/test/test.odt ADDED
Binary file
data/test/test.rb ADDED
@@ -0,0 +1,78 @@
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")
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flexy-odf-report
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - Sandro Duarte
9
+ - Mark von Zeschau
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-06-07 00:00:00 +02:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: rubyzip
19
+ prerelease: false
20
+ requirement: &id001 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "0"
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 0.9.4
29
+ type: :runtime
30
+ version_requirements: *id001
31
+ description: Generates ODF files, given a template (.odt) and data, replacing tags. Same as the original odf-report gem but adds some more features.
32
+ email: sandrods@gmail.com
33
+ executables: []
34
+
35
+ extensions: []
36
+
37
+ extra_rdoc_files:
38
+ - lib/odf-report.rb
39
+ - README.textile
40
+ files:
41
+ - lib/odf-report.rb
42
+ - odf-report.gemspec
43
+ - README.textile
44
+ - test/test.odt
45
+ - test/test.rb
46
+ - Manifest
47
+ - lib/odf-report/report.rb
48
+ - lib/odf-report/table.rb
49
+ - lib/odf-report/section.rb
50
+ - lib/odf-report/file_ops.rb
51
+ - lib/odf-report/hash_gsub.rb
52
+ has_rdoc: true
53
+ homepage: ""
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --line-numbers
59
+ - --inline-source
60
+ - --title
61
+ - Odf-report
62
+ - --main
63
+ - README.textile
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "1.2"
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.5.2
82
+ signing_key:
83
+ specification_version: 2
84
+ summary: Generates ODF files, given a template (.odt) and data, replacing tags. Same as the original odf-report gem but adds some more features.
85
+ test_files: []
86
+