Skip to content

Commit

Permalink
Added suport for sections
Browse files Browse the repository at this point in the history
  • Loading branch information
sandrods committed May 19, 2010
1 parent 8c40e63 commit 8f87627
Show file tree
Hide file tree
Showing 12 changed files with 622 additions and 292 deletions.
7 changes: 6 additions & 1 deletion Manifest
@@ -1,7 +1,12 @@
lib/odf-report.rb lib/odf-report.rb
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
odf-report.gemspec odf-report.gemspec
Rakefile
README.textile README.textile
test/test.odt test/test.odt
test/sections.odt
test/test.rb test/test.rb
Manifest Manifest
123 changes: 80 additions & 43 deletions README.textile
@@ -1,24 +1,24 @@
h1. ODF-REPORT h1. ODF-REPORT


Gem for generating .odt files by making strings, images and tables substitutions in a previously created .odt file. Gem for generating .odt files by making strings, images, tables and sections replacements in a previously created .odt file.


<hr/> <hr/>


h3. INSTALL h2. INSTALL


@gem install sandrods-odf-report --source=http://gems.github.com@ (sudo) gem install odf-report


<hr/> <hr/>


h3. USAGE h2. USAGE


h4. Step 1 -- the template h3. Step 1 -- the template


First of all, you need to create a .odt file to serve as a template First of all, you need to create a .odt file to serve as a template


Templates are normal .odt files with placeholders for Substitutions Templates are normal .odt files with placeholders for Substitutions


There are now three kinds of substitutions available: *fields*, *tables* and *images*. There are now *four* kinds of substitutions available: *fields*, *tables*, *images* and *sections*.


h4. Fields placeholders h4. Fields placeholders


Expand All @@ -27,11 +27,11 @@ It's just an upcase sentence, surrounded by brackets. It will be replaced for wa
In the folowing example: In the folowing example:


<pre> <pre>
report = ODFReport.new("Users/john/my_template.odt") do |r| report = ODFReport::Report.new("Users/john/my_template.odt") do |r|


r.add_field :user_name, @user.name r.add_field :user_name, @user.name
r.add_field :address, "My new address" r.add_field :address, "My new address"

end end
</pre> </pre>


Expand All @@ -43,21 +43,21 @@ h4. Table placeholders


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. 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.


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. 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.


As with Field placeholders, just insert a @[FIELD_NAME]@ in each cell and let the magic takes place. As with Field placeholders, just insert a @[FIELD_NAME]@ in each cell and let the magic takes place.


Taking the folowing example: Taking the folowing example:


<pre> <pre>
report = ODFReport.new("Users/john/my_template.odt") do |r| report = ODFReport::Report.new("Users/john/my_template.odt") do |r|


r.add_field "USER_NAME", @user.nome r.add_field "USER_NAME", @user.nome
r.add_field "ADDRESS", @user.address r.add_field "ADDRESS", @user.address


r.add_table("TABLE_1", @list_of_itens) do |row, item| r.add_table("TABLE_1", @list_of_itens, :header=>true) do |t|
row["ITEM_ID"] = item.id t.add_column(:item_id, :id)
row["DESCRIPTION"] = "==> #{item.description}" t.add_column(:description) do { |item| "==> #{item.description}" }
end end


end end
Expand All @@ -70,9 +70,9 @@ and considering you have a table like this in your template
| [ITEM_ID] | [DESCRIPTION] | | [ITEM_ID] | [DESCRIPTION] |
--------------------------------- ---------------------------------


* this is my lame attempt to draw a table. * this is my lame attempt to draw a table.
you don't suppose to type this. you don't suppose to type this.
you have to use an actual table. you have to use an actual table.
i don't know... just thought I'd mention it ;-) i don't know... just thought I'd mention it ;-)
</pre> </pre>


Expand All @@ -88,61 +88,98 @@ You can also assign any properties you want to the mock image and they will be k
An image replace would look like this: An image replace would look like this:


<pre> <pre>
report = ODFReport.new("Users/john/my_template.odt") do |r| report = ODFReport::Report.new("Users/john/my_template.odt") do |r|


r.add_image :graphics1, "/path/to/the/image.jpg" r.add_image :graphics1, "/path/to/the/image.jpg"


end end
</pre> </pre>


And that's it. h4. Sections (NEW!)

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.

*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.

Let's see an example:

<pre>

@invoices = Invoice.find(:all)

report = ODFReport::Report.new("reports/invoice.odt") do |r|

r.add_field(:title, "INVOICES REPORT")
r.add_field(:date, Date.today)

r.add_section("SC_INVOICE", @invoices) do |s|

s.add_field(:number) { |invoice| invoice.number.to_s.rjust(5, '0') }
s.add_field(:name, :customer_name)
s.add_field(:address, :customer_address)

s.add_table("TB_ITEMS", :items, :header => true) do |t|
t.add_column(:id)
t.add_column(:product) {|item| item.product.name }
t.add_column(:value, :product_value)
end

s.add_field(:total) do |invoice|
if invoice.status == 'CLOSED'
invoice.total
else
invoice.items.sum('product_value')}
end
end

end

end
</pre>

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.

In the above example, @s.add_table("TB_ITEMS", :items, :header => true) do |t|@, the @:items@ thing refers to a @invoice.items@. Easy, right?


<hr/><br/> <hr/><br/>


h4. Step 2 -- generating the document h3. Step 2 -- generating the document


It's fairly simple to generate the document. You can use this inside a Rails application or in a standalone script. It's fairly simple to generate the document. You can use this inside a Rails application or in a standalone script.


h4. Generating a document in a Rails application h4. Generating a document in a Rails application


In a controller, you can have a code like this: In a controller, you can have a code like this:

<pre> <pre>
def print def print


@ticket = Ticket.find(params[:id]) @ticket = Ticket.find(params[:id])


report = ODFReport.new("#{RAILS_ROOT}/app/reports/ticket.odt") do |r| report = ODFReport::Report.new("#{RAILS_ROOT}/app/reports/ticket.odt") do |r|

r.add_field(:id, @ticket.id.to_s) r.add_field(:id, @ticket.id.to_s)
r.add_field(:created_by, @ticket.created_by) r.add_field(:created_by, @ticket.created_by)
r.add_field(:created_at, @ticket.created_at.strftime("%d/%m/%Y - %H:%M")) r.add_field(:created_at, @ticket.created_at.strftime("%d/%m/%Y - %H:%M"))
r.add_field(:type, @ticket.type.name) r.add_field(:type, @ticket.type.name)
r.add_field(:status, @ticket.status_text) r.add_field(:status, @ticket.status_text)
r.add_field(:date, Time.now.strftime("%d/%m/%Y - %H:%M")) r.add_field(:date, Time.now.strftime("%d/%m/%Y - %H:%M"))
r.add_field(:solution, (@ticket.solution || '')) r.add_field(:solution, (@ticket.solution || ''))


r.add_table("OPERATORS", @ticket.operators) do | row, op | r.add_table("OPERATORS", @ticket.operators) do |t|
row["OPERATOR_NAME"] = "#{op.name} (#{op.department.short_name})" t.add_column(:operator_name) { |op| "#{op.name} (#{op.department.short_name})" }
end end

r.add_table("FIELDS", @ticket.fields) do | row, field |

if field.is_a?(String)
row["FIELD_NAME"] = 'Materials'
row["FIELD_VALUE"] = field
else
row["FIELD_NAME"] = field.name
row["FIELD_VALUE"] = field.text_value || ''
end


r.add_table("FIELDS", @ticket.fields) do |t|
t.add_column(:field_name, :name)
t.add_column(:field_value) { |field| field.text_value || "Empty" }
end end


end end


report_file_name = report.generate report_file_name = report.generate


send_file(report_file_name) send_file(report_file_name)


end end
</pre> </pre>
Expand All @@ -151,12 +188,12 @@ The @generate@ method will, er... generate the document in a temp dir and return


_That's all I have to say about that._ _That's all I have to say about that._


h4. Generating a document in a standalone script h4. Generating a document in a standalone script


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. 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.


<pre> <pre>
report = ODFReport.new("ticket.odt") do |r| report = ODFReport::Report.new("ticket.odt") do |r|


... populates the report ... ... populates the report ...


Expand Down
14 changes: 0 additions & 14 deletions Rakefile

This file was deleted.

0 comments on commit 8f87627

Please sign in to comment.