= clamsy
Ruby wrapper for generating a single pdf for multiple contexts from an odt template.
== 1. Basics
A template odt is just an ordinary odt (http://en.wikipedia.org/wiki/OpenDocument).
In order for it to function as a template, we just need to decorate it (just use
openoffice, pls don't buy ms office for that) with placeholders & embedded ruby code.
Under the hood, clamsy is using a slightly hacked version of the awesome tenjin
template engine (http://www.kuwata-lab.com/tenjin) to do the rendering. The following
is all u need to know to write odt templates:
- '{? ... ?}' represents embedded Ruby statement (this differs from vanilla tenjin)
- '${ ... }' represents embedded Ruby expression which is to be escaped
(eg. '& < > "' are escaped to '& < > "')
- '#{ ... }' represents embedded Ruby expression (u should really avoid using this)
== 2. Examples
=== 2.1. Text Replacement Example
Template Odt:
${@company_full_name}
${@company_address_line_1}
${@company_address_line_2}
S/N Item Description Amount (SGD)
{? @items.each_with_index do |item, i| ?}
${i+1} ${item.description} ${amount}
{? end ?}
Total ${total}
----------------------------------- Page 1 -
Code:
class Item
attr_reader :description, :amount
def initialize(description, amount)
@description, @amount = description, amount
end
end
items = [
Item.new('Shells (x2 Bags)', 10),
Item.new('Clams (x2 Bags)', 20)
]
context = {
:company_full_name => 'Monster Inc',
:company_address_line_1 => 'Planet Mars, Street xyz,',
:company_address_line_2 => 'Postal Code 009900',
:items => items,
:total => items.inject(0) {|sum, item| sum + item.amount }
}
Clamsy.process(
context,
path_to_template_odt, # eg. '/tmp/invoice.odt'
path_to_final_pdf, # eg. '/tmp/invoice.pdf'
)
Generated Pdf:
Monster Inc
Planet Mars, Street xyz,
Postal Code 009900
S/N Item Description Amount (SGD)
1 Shells (x2 Bags) 10
2 Clams (x2 Bags) 20
Total 30
----------------------------------- Page 1 -
=== 2.2: Multiple Contexts Example
Taking the above example one step further, if we have multiple contexts:
items << Item.new('Shrimps (x2 Bags)', 15)
items << Item.new('Prawns (x2 Bags)', 25)
contexts = [{
:company_full_name => 'Monster Inc',
:company_address_line_1 => 'Planet Mars, Street xyz,',
:company_address_line_2 => 'Postal Code 009900',
:items => items[0..1],
:total => items[0..1].inject(0) {|sum, item| sum + item.amount }
}, {
:company_full_name => 'Fisherman Inc',
:company_address_line_1 => 'Planet Jupiter, Street xyz,',
:company_address_line_2 => 'Postal Code 008800',
:items => items[2..3],
:total => items[2..3].inject(0) {|sum, item| sum + item.amount }
}]
Clamsy.process(
contexts,
path_to_template_odt, # eg. '/tmp/invoice.odt'
path_to_final_pdf # eg. '/tmp/invoice.pdf'
)
Generated Pdf:
Monster Inc
Planet Mars, Street xyz,
Postal Code 009900
S/N Item Description Amount (SGD)
1 Shells (x2 Bags) 10
2 Clams (x2 Bags) 20
Total 30
----------------------------------- Page 1 -
Fisherman Inc
Planet Jupiter, Street xyz,
Postal Code 008800
S/N Item Description Amount (SGD)
1 Shrimps (x2 Bags) 15
2 Prawns (x2 Bags) 25
Total 40
----------------------------------- Page 1 -
As you can see, (whether you like it or not) the pages are merely concatenated
together to form a single pdf !!
=== 2.3: Image Replacement Example
It is possible to replace images in an odt file, a useful feature if u need to insert
digital signature into the final pdf. To acheive this, u have to:
- insert a placeholder image into the odt file,
- resize & move it to your heart content
- right click on the picture, under [Picture ...]/[Options], assign a unique value
for [Name]
Template Odt:
~~~~~~~~~~~~~~~~~~
Hey | nice_guy_image |
~~~~~~~~~~~~~~~~~~
This is a gentle reminder that i still
owe you some money ...
~~~~~~~~~~~~~~~~~~~~~~
| my_signature_image |
~~~~~~~~~~~~~~~~~~~~~~
----------------------------------- Page 1 -
Assuming 'nice_guy_image' & 'my_signature_image' as names of the images, the following
code does the appropriate replacing of images:
Clamsy.process(
context = {:_pictures => {
:nice_guy_image => path_to_avatar_image, # eg. '/tmp/handsome.png'
:my_signature_image => path_to_signature_image # eg. '/tmp/signature.png'
}},
path_to_template_odt # eg. '/tmp/confession.odt'
path_to_final_pdf # eg. '/tmp/confession.pdf'
)
== 3. Configuration
(see http://wiki.github.com/ngty/clamsy/configuration)
== 4. Pre-requisites
- Make sure openoffice, java & ghostscript are installed
== TODO
- address security risk of user running destructive commands within embedded ruby in odt
template
- support for other platforms (eg. windows & jruby)
- turn off non-santized ruby expression by default (since the generated doc easily breaks
when underlying xml is invalid)
- automate cups-pdf printer setup
== Note on Patches/Pull Requests
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don't break it in a
future version unintentionally.
- Commit, do not mess with rakefile, version, or history. (if you want to have your own
version, that is fine but bump version in a commit by itself I can ignore when I pull)
- Send me a pull request. Bonus points for topic branches.
== Contacts
Written 2010 by:
- NgTzeYang, contact http://github.com/ngty
- JasonOng, contact http://github.com/jasonong
- ZhenyiTan, contact http://github.com/zhenyi
Released under the MIT license