Skip to content

Instantly share code, notes, and snippets.

@practicingruby
Last active August 29, 2015 13:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save practicingruby/8714146 to your computer and use it in GitHub Desktop.
Save practicingruby/8714146 to your computer and use it in GitHub Desktop.
require_relative "helper"
### Parse the sections of the document into a params dictionary
parser = FormLetter::Parser.new
parser.rewrite(:emails, :deadline)
parser.rewrite(:date) { Date.today.strftime("%b %d, %Y") }
# this would come from a database or other source,
# but you get the idea
parser.rewrite(:customer_name) do
["Gregory", "Brad", "James", "Daniel", "Jonathan" ].sample
end
params = parser.parse(File.read("letter.txt"))
## Set relevant formatting for different sections
formatting = {
:company => { :styles => [:bold] },
:company_subtext => { :size => 8 },
:company_header => { :align => :center, :leading => 4, :color => "555555" },
:company_address => { :align => :center, :color => "555555", :size => 10 },
:from => { :align => :left, :color => "555555", :size => 10 },
:contact => { :align => :right, :color => "555555", :size => 10 },
:body => { :size => 10, :inline_format => true },
:footer => { :size => 8, :color => "555555" }
}
### Generate the letter
letter = FormLetter.new(params, formatting)
letter.update do
font "Helvetica"
header_box(:left) do
move_down 0.75.in
text(:from)
end
header_box(:center) do
text_group [:company, :company_subtext], :company_header
text(:company_address)
end
header_box(:right) do
move_down 0.75.in
text(:contact)
end
font "Times-Roman"
move_down 2.in
body do
letter.text(:body) # NOTE: nbsp in content
end
move_cursor_to 0.5.in
font "Helvetica"
text(:footer)
end
letter.save_as("letter.pdf")
require "ostruct"
require "bundler"
Bundler.require
require "prawn/measurement_extensions"
Prawn.debug = true
module PrawnDSL
def document
@document ||= Prawn::Document.new
end
def method_missing(m, *a, &b)
document.send(m, *a, &b)
end
def update(&b)
instance_eval(&b)
end
def save_as(filename)
document.render_file(filename)
end
end
class FormLetter
include PrawnDSL
def initialize(params, styles)
@params = params
@styles = styles
end
def text(content_key)
document.text(@params[content_key].strip + "\n",
@styles.fetch(content_key, {}))
end
def text_group(fragments, style_key=nil)
document.formatted_text(
fragments.map { |e| fragment(e) },
@styles.fetch(style_key, {}))
end
def header_box(position)
float do
span(bounds.width / 3.0, :position => position) do
yield
end
end
end
def body
span(6.5.in, :position => :center) { yield }
end
private
def fragment(content_key)
{ :text => @params[content_key].strip + "\n" }
.merge(@styles.fetch(content_key, {}))
end
end
class FormLetter::Parser
def initialize
@rewrites = {}
end
def rewrite(*patterns, &block)
return rewrite_dynamic(patterns.first, &block) if block
patterns.each do |pattern|
key = ":#{pattern}:"
@rewrites[key] = ->(e) { e[pattern.to_s] }
end
end
def parse(text)
params = OpenStruct.new
section = nil
text.lines.each do |e|
if e[/^::(.*)/, 1]
section = $1
elsif section
@rewrites.select { |k,v| e.include?(k) }
.each { |k,v| e.gsub!(k, v.call(params).strip) }
(params[section] ||= "") << e
else
warn "Section not set!"
end
end
params
end
private
def rewrite_dynamic(pattern, &block)
key = ":#{pattern}:"
@rewrites[key] = block
end
end
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
::from
Enrico O'Keefe
Florine Grant
::contact
Phone: 203-555-1234
Fax: 203-555-4321
::company
O'KEEFE AND GRANT, P.C.
::company_subtext
CERTIFIED PUBLIC ACCOUNTANTS
::company_address
24410 Rice Meadow Road • Suite A
New Haven, Connecticut 06512
::deadline
March 31, 2014
::emails
        <u>enrico@okgracpas.com</u>
        <u>florine@okgracpas.com</u>
::footer
Members:
American Institute of Certified Public Accountants
Connecticut Society of Certified Public Accountants
::body
:date:
Dear :customer_name:,
It's that time of year again and in order to assist you in gathering the necessary records needed to prepare your 2013 tax returns, we have compiled the enclosed cheklist for you to complete.
Just a reminder, your 2013 returns must be electronically filed as required by the Internal Revenue Service. Also, our fee is expected to be paid at the time your tax return is completed. <strong>Fee must be paid before return is filed. For your convenience, we accept credit cards.</strong>
If you receive a refund we recommend that you have it direct deposited. This results in a quicker and dafer way to receive your refund. Please complete and return the enclosed information and return it to us when you send in your tax information.
When you send in your information, also give us your email address if you have one so that we may contact you should we need any additional information. Also, please let us know if you would like to pick up your return when it is completed or if you would like it mailed to you.
Please send in your information before :deadline:. If we receive your information after that date, there is no guarantee that your returns will be processed by the tax filing deadline and an extension will be filed for you.
If you have any questions, please do not heasitate to give us a call, or email us at:
:emails:
Sincerely,
O'KEEFE AND GRANT, P.C.
Certified Public Accountants
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment