Skip to content
This repository
Newer
Older
100644 228 lines (137 sloc) 7.206 kb
657c1c28 »
2009-07-28 Initial Commit
1 h1. ODF-REPORT
2
8f876275 »
2010-05-19 Added suport for sections
3 Gem for generating .odt files by making strings, images, tables and sections replacements in a previously created .odt file.
657c1c28 »
2009-07-28 Initial Commit
4
8f876275 »
2010-05-19 Added suport for sections
5 h2. INSTALL
657c1c28 »
2009-07-28 Initial Commit
6
8f876275 »
2010-05-19 Added suport for sections
7 (sudo) gem install odf-report
657c1c28 »
2009-07-28 Initial Commit
8
8f876275 »
2010-05-19 Added suport for sections
9 h2. USAGE
657c1c28 »
2009-07-28 Initial Commit
10
8f876275 »
2010-05-19 Added suport for sections
11 h3. Step 1 -- the template
657c1c28 »
2009-07-28 Initial Commit
12
13 First of all, you need to create a .odt file to serve as a template
14
15 Templates are normal .odt files with placeholders for Substitutions
16
8f876275 »
2010-05-19 Added suport for sections
17 There are now *four* kinds of substitutions available: *fields*, *tables*, *images* and *sections*.
657c1c28 »
2009-07-28 Initial Commit
18
4d1d0f04 »
2010-05-19 readme update
19 h3. Fields placeholders
657c1c28 »
2009-07-28 Initial Commit
20
21 It's just an upcase sentence, surrounded by brackets. It will be replaced for wathever value you supply.
22
23 In the folowing example:
24
25 <pre>
8f876275 »
2010-05-19 Added suport for sections
26 report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
657c1c28 »
2009-07-28 Initial Commit
27
28 r.add_field :user_name, @user.name
29 r.add_field :address, "My new address"
8f876275 »
2010-05-19 Added suport for sections
30
657c1c28 »
2009-07-28 Initial Commit
31 end
32 </pre>
33
34 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@
35
36 It's as simple as that.
37
4d1d0f04 »
2010-05-19 readme update
38
39 h3. Table placeholders
657c1c28 »
2009-07-28 Initial Commit
40
41 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.
42
8f876275 »
2010-05-19 Added suport for sections
43 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.
657c1c28 »
2009-07-28 Initial Commit
44
45 As with Field placeholders, just insert a @[FIELD_NAME]@ in each cell and let the magic takes place.
46
47 Taking the folowing example:
48
49 <pre>
8f876275 »
2010-05-19 Added suport for sections
50 report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
657c1c28 »
2009-07-28 Initial Commit
51
52 r.add_field "USER_NAME", @user.nome
53 r.add_field "ADDRESS", @user.address
54
8f876275 »
2010-05-19 Added suport for sections
55 r.add_table("TABLE_1", @list_of_itens, :header=>true) do |t|
56 t.add_column(:item_id, :id)
57 t.add_column(:description) do { |item| "==> #{item.description}" }
657c1c28 »
2009-07-28 Initial Commit
58 end
59
60 end
61 </pre>
62
63 and considering you have a table like this in your template
64
65 <pre>
2e9aaf83 »
2009-07-29 Updated Documentation
66 ---------------------------------
67 | [ITEM_ID] | [DESCRIPTION] |
68 ---------------------------------
69
8f876275 »
2010-05-19 Added suport for sections
70 * this is my lame attempt to draw a table.
71 you don't suppose to type this.
72 you have to use an actual table.
2e9aaf83 »
2009-07-29 Updated Documentation
73 i don't know... just thought I'd mention it ;-)
657c1c28 »
2009-07-28 Initial Commit
74 </pre>
75
76 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.
77
78 Any format applied to the fields in the template will be preserved.
79
4d1d0f04 »
2010-05-19 readme update
80
81 h3. Images
b34b71cd »
2009-09-17 Update Readme
82
83 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.
84 You can also assign any properties you want to the mock image and they will be kept once the image is replaced.
85
86 An image replace would look like this:
87
88 <pre>
8f876275 »
2010-05-19 Added suport for sections
89 report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
b34b71cd »
2009-09-17 Update Readme
90
91 r.add_image :graphics1, "/path/to/the/image.jpg"
92
93 end
94 </pre>
95
4d1d0f04 »
2010-05-19 readme update
96
56851430 »
2011-09-23 update readme
97 h3. Sections
8f876275 »
2010-05-19 Added suport for sections
98
57f7c422 »
2012-05-29 Typo fix
99 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 Section in OpenOffice is as easy as select menu *Insert* and then *Section...*, and then choose a name for it.
8f876275 »
2010-05-19 Added suport for sections
100
56851430 »
2011-09-23 update readme
101 *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.
8f876275 »
2010-05-19 Added suport for sections
102
103 Let's see an example:
104
105 <pre>
106
107 @invoices = Invoice.find(:all)
108
109 report = ODFReport::Report.new("reports/invoice.odt") do |r|
110
111 r.add_field(:title, "INVOICES REPORT")
112 r.add_field(:date, Date.today)
113
114 r.add_section("SC_INVOICE", @invoices) do |s|
115
116 s.add_field(:number) { |invoice| invoice.number.to_s.rjust(5, '0') }
117 s.add_field(:name, :customer_name)
118 s.add_field(:address, :customer_address)
119
120 s.add_table("TB_ITEMS", :items, :header => true) do |t|
121 t.add_column(:id)
122 t.add_column(:product) {|item| item.product.name }
123 t.add_column(:value, :product_value)
124 end
125
126 s.add_field(:total) do |invoice|
127 if invoice.status == 'CLOSED'
128 invoice.total
129 else
130 invoice.items.sum('product_value')}
131 end
132 end
133
56851430 »
2011-09-23 update readme
134 s.add_section("SUB_NOTES", :notes) do |s1|
135
136 s1.add_field(:note_title) { |n| n.title }
137
138 s1.add_table ...
139
140 end
141
8f876275 »
2010-05-19 Added suport for sections
142 end
143
144 end
145 </pre>
146
147 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.
148
149 In the above example, @s.add_table("TB_ITEMS", :items, :header => true) do |t|@, the @:items@ thing refers to a @invoice.items@. Easy, right?
b34b71cd »
2009-09-17 Update Readme
150
657c1c28 »
2009-07-28 Initial Commit
151 <hr/><br/>
152
8f876275 »
2010-05-19 Added suport for sections
153 h3. Step 2 -- generating the document
657c1c28 »
2009-07-28 Initial Commit
154
155 It's fairly simple to generate the document. You can use this inside a Rails application or in a standalone script.
156
8f876275 »
2010-05-19 Added suport for sections
157 h4. Generating a document in a Rails application
657c1c28 »
2009-07-28 Initial Commit
158
159 In a controller, you can have a code like this:
8f876275 »
2010-05-19 Added suport for sections
160
657c1c28 »
2009-07-28 Initial Commit
161 <pre>
162 def print
163
f098edbf »
2009-08-04 Tiny README update
164 @ticket = Ticket.find(params[:id])
165
eaace51d »
2013-05-31 Added information about using of RAILS_ROOT at new Rails version.
166 # For Rails 3 or latest replace #{RAILS_ROOT} to #{Rails.root}
8f876275 »
2010-05-19 Added suport for sections
167 report = ODFReport::Report.new("#{RAILS_ROOT}/app/reports/ticket.odt") do |r|
168
169 r.add_field(:id, @ticket.id.to_s)
657c1c28 »
2009-07-28 Initial Commit
170 r.add_field(:created_by, @ticket.created_by)
171 r.add_field(:created_at, @ticket.created_at.strftime("%d/%m/%Y - %H:%M"))
8f876275 »
2010-05-19 Added suport for sections
172 r.add_field(:type, @ticket.type.name)
173 r.add_field(:status, @ticket.status_text)
174 r.add_field(:date, Time.now.strftime("%d/%m/%Y - %H:%M"))
175 r.add_field(:solution, (@ticket.solution || ''))
657c1c28 »
2009-07-28 Initial Commit
176
8f876275 »
2010-05-19 Added suport for sections
177 r.add_table("OPERATORS", @ticket.operators) do |t|
178 t.add_column(:operator_name) { |op| "#{op.name} (#{op.department.short_name})" }
657c1c28 »
2009-07-28 Initial Commit
179 end
b34b71cd »
2009-09-17 Update Readme
180
8f876275 »
2010-05-19 Added suport for sections
181 r.add_table("FIELDS", @ticket.fields) do |t|
182 t.add_column(:field_name, :name)
183 t.add_column(:field_value) { |field| field.text_value || "Empty" }
657c1c28 »
2009-07-28 Initial Commit
184 end
185
186 end
187
188 report_file_name = report.generate
189
8f876275 »
2010-05-19 Added suport for sections
190 send_file(report_file_name)
657c1c28 »
2009-07-28 Initial Commit
191
192 end
193 </pre>
194
195 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.
196
197 _That's all I have to say about that._
198
8f876275 »
2010-05-19 Added suport for sections
199 h4. Generating a document in a standalone script
657c1c28 »
2009-07-28 Initial Commit
200
201 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.
202
203 <pre>
8f876275 »
2010-05-19 Added suport for sections
204 report = ODFReport::Report.new("ticket.odt") do |r|
657c1c28 »
2009-07-28 Initial Commit
205
206 ... populates the report ...
207
208 end
209
210 report.generate("./documents/")
211 </pre>
212
213 <hr/>
214
215 h3. REQUIREMENTS
216
217 *rubyzip*: for manipulating the contents of the odt file, since it's actually a zip file.
56851430 »
2011-09-23 update readme
218 *nokogiri*: for parsing and manipulating the document xml files.
657c1c28 »
2009-07-28 Initial Commit
219
220
f098edbf »
2009-08-04 Tiny README update
221 <hr/>
222
223 h3. THE FUTURE
224
225 Well, this is my first attempt. This gem was extracted from an actual project we developed internally, to fulfill our specific needs.
226
57f7c422 »
2012-05-29 Typo fix
227 That said, I would really appreciate any input you can come up with. Critics, suggestions, bug reports are welcome and will be thoroughly examined.
Something went wrong with that request. Please try again.