sandrods-odf-report 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest ADDED
@@ -0,0 +1,7 @@
1
+ lib/odf-report.rb
2
+ odf-report.gemspec
3
+ Rakefile
4
+ README.textile
5
+ test/test.odt
6
+ test/test.rb
7
+ Manifest
data/README.textile ADDED
@@ -0,0 +1,150 @@
1
+ h1. ODF-REPORT
2
+
3
+ Gem for generating .odt files by making strings substitution in a previously created .odt file.
4
+
5
+ <hr/>
6
+
7
+ h3. INSTALL
8
+
9
+ @gem install sandrods-odf-report --source=http://gems.github.com@
10
+
11
+ <hr/>
12
+
13
+ h3. USAGE
14
+
15
+ h4. Step 1 -- the template
16
+
17
+ First of all, you need to create a .odt file to serve as a template
18
+
19
+ Templates are normal .odt files with placeholders for Substitutions
20
+
21
+ There are two kinds of substitutions available: *fields* and *tables*
22
+
23
+ h4. Fields placeholders
24
+
25
+ It's just an upcase sentence, surrounded by brackets. It will be replaced for wathever value you supply.
26
+
27
+ In the folowing example:
28
+
29
+ <pre>
30
+ report = ODFReport.new("Users/john/my_template.odt") do |r|
31
+
32
+ r.add_field :user_name, @user.name
33
+ r.add_field :address, "My new address"
34
+
35
+ end
36
+ </pre>
37
+
38
+ 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@
39
+
40
+ It's as simple as that.
41
+
42
+ h4. Table placeholders
43
+
44
+ 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.
45
+
46
+ If the table has two rows, the first one will be treated as a *header* and left untouched. Otherwise you should use a table with one row only.
47
+
48
+ As with Field placeholders, just insert a @[FIELD_NAME]@ in each cell and let the magic takes place.
49
+
50
+ Taking the folowing example:
51
+
52
+ <pre>
53
+ report = ODFReport.new("Users/john/my_template.odt") do |r|
54
+
55
+ r.add_field "USER_NAME", @user.nome
56
+ r.add_field "ADDRESS", @user.address
57
+
58
+ r.add_table("TABLE_1", @list_of_itens) do |row, item|
59
+ row["ITEM_ID"] = item.id
60
+ row["DESCRIPTION"] = "==> #{item.description}"
61
+ end
62
+
63
+ end
64
+ </pre>
65
+
66
+ and considering you have a table like this in your template
67
+
68
+ <pre>
69
+ ----------------------------
70
+ | [ITEM_ID] | [DESCRIPTON] |
71
+ ----------------------------
72
+ </pre>
73
+
74
+ 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.
75
+
76
+ Any format applied to the fields in the template will be preserved.
77
+
78
+ <hr/><br/>
79
+
80
+ h4. Step 2 -- generating the document
81
+
82
+ It's fairly simple to generate the document. You can use this inside a Rails application or in a standalone script.
83
+
84
+ h4. Generating a document in a Rails application
85
+
86
+ In a controller, you can have a code like this:
87
+
88
+ <pre>
89
+ def print
90
+
91
+ report = ODFReport.new("#{RAILS_ROOT}/app/reports/ticket.odt") do |r|
92
+
93
+ r.add_field(:id, @ticket.id.to_s)
94
+ r.add_field(:created_by, @ticket.created_by)
95
+ r.add_field(:created_at, @ticket.created_at.strftime("%d/%m/%Y - %H:%M"))
96
+ r.add_field(:type, @ticket.type.name)
97
+ r.add_field(:status, @ticket.status_text)
98
+ r.add_field(:date, Time.now.strftime("%d/%m/%Y - %H:%M"))
99
+ r.add_field(:solution, (@ticket.solution || ''))
100
+
101
+ r.add_table("OPERATORS", @ticket.operators) do | row, op |
102
+ row["OPERATOR_NAME"] = "#{op.name} (#{op.department.short_name})"
103
+ end
104
+
105
+ r.add_table("FIELDS", @ticket.fields) do | row, field |
106
+
107
+ if field.is_a?(String)
108
+ row["FIELD_NAME"] = 'Materials'
109
+ row["FIELD_VALUE"] = field
110
+ else
111
+ row["FIELD_NAME"] = field.name
112
+ row["FIELD_VALUE"] = field.text_value || ''
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ report_file_name = report.generate
120
+
121
+ send_file(report_file_name)
122
+
123
+ end
124
+ </pre>
125
+
126
+ 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.
127
+
128
+ _That's all I have to say about that._
129
+
130
+ h4. Generating a document in a standalone script
131
+
132
+ 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.
133
+
134
+ <pre>
135
+ report = ODFReport.new("ticket.odt") do |r|
136
+
137
+ ... populates the report ...
138
+
139
+ end
140
+
141
+ report.generate("./documents/")
142
+ </pre>
143
+
144
+ <hr/>
145
+
146
+ h3. REQUIREMENTS
147
+
148
+ *rubyzip*: for manipulating the contents of the odt file, since it's actually a zip file.
149
+
150
+
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('odf-report', '0.1.1') do |p|
6
+ p.description = "Generates ODF files, given a template (.odt) and data, replacing tags"
7
+ p.url = ""
8
+ p.author = "Sandro Duarte"
9
+ p.email = "sandrods@gmail.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ p.runtime_dependencies = ['rubyzip >= 0.9.1']
13
+ end
14
+
data/lib/odf-report.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'rubygems'
2
+ require 'zip/zipfilesystem'
3
+ require 'fileutils'
4
+
5
+ class ODFReport
6
+
7
+ def initialize(template_name, &block)
8
+ @template = template_name
9
+ @data={:values=>{}, :tables=>{}}
10
+
11
+ @tmp_dir = Dir.tmpdir + "/" + random_filename(:prefix=>'odt_')
12
+ Dir.mkdir(@tmp_dir) unless File.exists? @tmp_dir
13
+
14
+ yield self
15
+ end
16
+
17
+ def add_field(field_tag, value)
18
+ @data[:values][field_tag] = value
19
+ end
20
+
21
+ def add_table(table_tag, collection, &block)
22
+
23
+ @data[:tables][table_tag] = []
24
+
25
+ collection.each do |item|
26
+ row = {}
27
+ yield(row, item)
28
+ @data[:tables][table_tag] << row
29
+ end
30
+
31
+ end
32
+
33
+ def generate(dest = nil)
34
+
35
+ if dest
36
+
37
+ FileUtils.cp(@template, dest)
38
+ new_file = dest
39
+
40
+ else
41
+
42
+ FileUtils.cp(@template, @tmp_dir)
43
+ new_file = "#{@tmp_dir}/#{File.basename(@template)}"
44
+
45
+ end
46
+
47
+ %w(content.xml styles.xml).each do |content_file|
48
+
49
+ update_file_from_zip(new_file, content_file) do |txt|
50
+
51
+ replace_fields!(txt)
52
+ replace_tables!(txt)
53
+
54
+ end
55
+
56
+ end
57
+
58
+ new_file
59
+
60
+ end
61
+
62
+ private
63
+
64
+ def update_file_from_zip(zip_file, content_file, &block)
65
+
66
+ Zip::ZipFile.open(zip_file) do |z|
67
+ cont = "#{@tmp_dir}/#{content_file}"
68
+
69
+ z.extract(content_file, cont)
70
+
71
+ txt = ''
72
+
73
+ File.open(cont, "r") do |f|
74
+ txt = f.read
75
+ end
76
+
77
+ yield(txt)
78
+
79
+ File.open(cont, "w") do |f|
80
+ f.write(txt)
81
+ end
82
+
83
+ z.replace(content_file, cont)
84
+ end
85
+
86
+ end
87
+
88
+
89
+ def replace_fields!(content)
90
+ hash_gsub!(content, @data[:values])
91
+ end
92
+
93
+
94
+ def replace_tables!(content)
95
+
96
+ @data[:tables].each do |table_name, records|
97
+
98
+ # search for the table inside the content
99
+ table_rgx = Regexp.new("(<table:table table:name=\"#{table_name}.*?>.*?<\/table:table>)", "m")
100
+ table_match = content.match(table_rgx)
101
+
102
+ if table_match
103
+ table = table_match[0]
104
+
105
+ # extract the table from the content
106
+ content.gsub!(table, "[TABLE_#{table_name}]")
107
+
108
+ # search for the table:row's
109
+ row_rgx = Regexp.new("(<table:table-row.*?<\/table:table-row>)", "m")
110
+
111
+ # use scan (instead of match) as the table can have more than one table-row (header and data)
112
+ # and scan returns all matches
113
+ row_match = table.scan(row_rgx)
114
+
115
+ unless row_match.empty?
116
+
117
+ # If there more than one line in the table, takes the second entry (row_match[1])
118
+ # since the first one represents the column header.
119
+ # If there just one line, takes the first line. Besides, since the entry is an Array itself,
120
+ # takes the entry's first element ( entry[0] )
121
+ model_row = (row_match[1] || row_match[0])[0]
122
+
123
+ # extract the row from the table
124
+ table.gsub!(model_row, "[ROW_#{table_name}]")
125
+
126
+ new_rows = ""
127
+
128
+ # for each record
129
+ records.each do |_values|
130
+
131
+ # generates one new row (table-row), based in the model extracted
132
+ # from the original table
133
+ tmp_row = model_row.dup
134
+
135
+ # replace values in the model_row and stores in new_rows
136
+ hash_gsub!(tmp_row, _values)
137
+
138
+ new_rows << tmp_row
139
+ end
140
+
141
+ # replace back the lines into the table
142
+ table.gsub!("[ROW_#{table_name}]", new_rows)
143
+
144
+ end # unless row_match.empty?
145
+
146
+ # replace back the table into content
147
+ content.gsub!("[TABLE_#{table_name}]", table)
148
+
149
+ end # if table match
150
+
151
+ end # tables each
152
+
153
+ end # replace_tables
154
+
155
+ def hash_gsub!(_text, hash_of_values)
156
+ hash_of_values.each do |key, val|
157
+ _text.gsub!("[#{key.to_s.upcase}]", val.to_s) unless val.nil?
158
+ end
159
+ end
160
+
161
+ def random_filename(opts={})
162
+ opts = {:chars => ('0'..'9').to_a + ('A'..'F').to_a + ('a'..'f').to_a,
163
+ :length => 24, :prefix => '', :suffix => '',
164
+ :verify => true, :attempts => 10}.merge(opts)
165
+ opts[:attempts].times do
166
+ filename = ''
167
+ opts[:length].times { filename << opts[:chars][rand(opts[:chars].size)] }
168
+ filename = opts[:prefix] + filename + opts[:suffix]
169
+ return filename unless opts[:verify] && File.exists?(filename)
170
+ end
171
+ nil
172
+ end
173
+
174
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{odf-report}
5
+ s.version = "0.1.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Sandro Duarte"]
9
+ s.date = %q{2009-07-28}
10
+ s.description = %q{Generates ODF files, given a template (.odt) and data, replacing tags}
11
+ s.email = %q{sandrods@gmail.com}
12
+ s.extra_rdoc_files = ["lib/odf-report.rb", "README.textile"]
13
+ s.files = ["lib/odf-report.rb", "odf-report.gemspec", "Rakefile", "README.textile", "test/test.odt", "test/test.rb", "Manifest"]
14
+ s.has_rdoc = true
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.rubyforge_project = %q{odf-report}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Generates ODF files, given a template (.odt) and data, replacing tags}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<rubyzip>, [">= 0", "= 0.9.1"])
28
+ else
29
+ s.add_dependency(%q<rubyzip>, [">= 0", "= 0.9.1"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<rubyzip>, [">= 0", "= 0.9.1"])
33
+ end
34
+ end
data/test/test.odt ADDED
Binary file
data/test/test.rb ADDED
@@ -0,0 +1,36 @@
1
+ require '../lib/odf-report'
2
+
3
+ col1 = []
4
+ col1 << {:nome=>"Campo zero um", :id=>"Campo dois", :ender=>"tres tres"}
5
+ col1 << {:nome=>"zero um", :id=>"dois", :ender=>"tres"}
6
+ col1 << {:nome=>"Campo um", :id=>"Campo erthe dois", :ender=>"tres tres tres"}
7
+
8
+ col2 = []
9
+ col2 << {:nome=>"Campo zero um", :id=>"Campo dois", :ender=>"tres tres", :fone=>99025668, :cep=>"90420-002"}
10
+ col2 << {:nome=>"sandro", :id=>"45", :ender=>"minha casa", :fone=>88774451, :cep=>"90490-002"}
11
+ col2 << {:nome=>"ellen bicca", :id=>"77", :ender=>"casa dela", :fone=>77025668, :cep=>"94420-002"}
12
+
13
+ report = ODFReport.new("test.odt") do |r|
14
+
15
+ r.add_field("CAMPO_CAB", "Este campo estava no cabecalho")
16
+
17
+ r.add_field("TAG_01", "Nova tag")
18
+ r.add_field("TAG_02", "TAG-2 -> Nova tag")
19
+
20
+ r.add_table("TABELA_01", col1) do |row, item|
21
+ row["CAMPO_01"] = item[:id]
22
+ row["CAMPO_02"] = item[:nome]
23
+ row["CAMPO_03"] = item[:ender]
24
+ end
25
+
26
+ r.add_table("TABELA_02", col2) do |row, item|
27
+ row["CAMPO_04"] = item[:id]
28
+ row["CAMPO_05"] = item[:nome]
29
+ row["CAMPO_06"] = item[:ender]
30
+ row["CAMPO_07"] = item[:fone]
31
+ row["CAMPO_08"] = item[:cep]
32
+ end
33
+
34
+ end
35
+
36
+ report.generate("result.odt")
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sandrods-odf-report
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Sandro Duarte
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-28 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rubyzip
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ - - "="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.1
27
+ version:
28
+ description: Generates ODF files, given a template (.odt) and data, replacing tags
29
+ email: sandrods@gmail.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files:
35
+ - lib/odf-report.rb
36
+ - README.textile
37
+ files:
38
+ - lib/odf-report.rb
39
+ - odf-report.gemspec
40
+ - Rakefile
41
+ - README.textile
42
+ - test/test.odt
43
+ - test/test.rb
44
+ - Manifest
45
+ has_rdoc: true
46
+ homepage: ""
47
+ licenses:
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --line-numbers
51
+ - --inline-source
52
+ - --title
53
+ - Odf-report
54
+ - --main
55
+ - README.textile
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "1.2"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project: odf-report
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 2
76
+ summary: Generates ODF files, given a template (.odt) and data, replacing tags
77
+ test_files: []
78
+