Skip to content

Instantly share code, notes, and snippets.

@motin
Forked from karmi/.gitignore
Created June 1, 2011 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motin/1003260 to your computer and use it in GitHub Desktop.
Save motin/1003260 to your computer and use it in GitHub Desktop.
This fork adds more metadata and also shows the first seven tasks within each story. Original description: Script to generate PDF cards suitable for planning poker from Pivotal Tracker [http://www.pivotaltracker.com/] CSV export. Inspired by Bryan Helmkam
.DS_Store
*.csv
*.pdf
#!/usr/bin/env ruby
# Script to generate PDF cards suitable for planning poker
# from Pivotal Tracker [http://www.pivotaltracker.com/] CSV export.
# Inspired by Bryan Helmkamp's http://github.com/brynary/features2cards/
# Example output: http://img.skitch.com/20100522-d1kkhfu6yub7gpye97ikfuubi2.png
# This fork adds more metadata and also shows the first seven tasks within each story.
require 'rubygems'
require 'fastercsv'
require 'ostruct'
require 'term/ansicolor'
require 'prawn'
require 'prawn/layout/grid'
class String; include Term::ANSIColor; end
file = ARGV.first
unless file
puts "[!] Please provide a path to CSV file"
exit 1
end
# --- Read the CSV file -------------------------------------------------------
stories = FasterCSV.read(file)
headers = stories.shift
# p headers
# p stories
# --- Hold story in Card class
class Card < OpenStruct
def type
@table[:type]
end
end
# --- Create cards objects
cards = stories.map do |story|
attrs = { :title => story[1] || '',
:body => story[14] || '',
:type => story[6] || '.'*50,
:labels => story[2] || '.'*50,
:state => story[8] || '.'*50,
:iteration => story[3] || '…',
:points => story[7] || '...',
:task1 => story[20] || '.'*30,
:task1status => if story[21] == "completed" then "[X]" else "[ ]" end,
:task2 => story[22] || '.'*30,
:task2status => if story[23] == "completed" then "[X]" else "[ ]" end,
:task3 => story[24] || '.'*30,
:task3status => if story[25] == "completed" then "[X]" else "[ ]" end,
:task4 => story[26] || '.'*30,
:task4status => if story[27] == "completed" then "[X]" else "[ ]" end,
:task5 => story[28] || '.'*30,
:task5status => if story[29] == "completed" then "[X]" else "[ ]" end,
:task6 => story[30] || '.'*30,
:task6status => if story[31] == "completed" then "[X]" else "[ ]" end,
:task7 => story[32] || '.'*30,
:task7status => if story[33] == "completed" then "[X]" else "[ ]" end,
:task8 => story[34] || '.'*30,
:task8status => if story[35] == "completed" then "[X]" else "[ ]" end,
:task9 => story[36] || '.'*30,
:task9status => if story[37] == "completed" then "[X]" else "[ ]" end,
:task10 => story[38] || '.'*30,
:task10status => if story[39] == "completed" then "[X]" else "[ ]" end,
:task11 => story[40] || '.'*30,
:task11status => if story[41] == "completed" then "[X]" else "[ ]" end,
:task12 => story[42] || '.'*30,
:task12status => if story[43] == "completed" then "[X]" else "[ ]" end,
:task13 => story[44] || '.'*30,
:task13status => if story[45] == "completed" then "[X]" else "[ ]" end,
:task14 => story[46] || '.'*30,
:task14status => if story[47] == "completed" then "[X]" else "[ ]" end,
:task15 => story[48] || '.'*30,
:task15status => if story[49] == "completed" then "[X]" else "[ ]" end,
:owner => story[13] || '.'*50}
Card.new attrs
end
# p cards
# --- Generate PDF with Prawn & Prawn::Document::Grid
begin
outfile = File.basename(file, ".csv")
Prawn::Document.generate("#{outfile}.pdf",
:page_layout => :landscape,
:margin => [25, 25, 50, 25],
:page_size => 'A4') do |pdf|
@num_cards_on_page = 0
pdf.font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
cards.each_with_index do |card, i|
# --- Split pages
if i > 0 and i % 4 == 0
# puts "New page..."
pdf.start_new_page
@num_cards_on_page = 1
else
@num_cards_on_page += 1
end
# --- Define 2x2 grid
pdf.define_grid(:columns => 2, :rows => 2, :gutter => 42)
# pdf.grid.show_all
row = (@num_cards_on_page+1) / 4
column = i % 2
# p @num_cards_on_page
# p [ row, column ]
padding = 12
cell = pdf.grid( row, column )
cell.bounding_box do
pdf.stroke_color = "666666"
pdf.stroke_bounds
# --- Write content
pdf.bounding_box [pdf.bounds.left+padding, pdf.bounds.top-padding], :width => cell.width-padding*2 do
pdf.text card.title, :size => 14
# pdf.text "\n", :size => 6
pdf.fill_color "444444"
pdf.text card.body, :size => 10
pdf.fill_color "000000"
end
pdf.text_box "Points: " + card.points,
:size => 12, :at => [12, 50], :width => cell.width-18
pdf.text_box "Owner: " + card.owner,
:size => 8, :at => [12, 18], :width => cell.width-18
# tasks
pdf.text_box card.task1status, :size => 8, :align => :left, :at => [12, 125], :width => 18
pdf.text_box card.task1, :size => 8, :align => :left, :at => [12+18, 125], :width => cell.width-18
pdf.text_box card.task2status, :size => 8, :align => :left, :at => [12, 125-10*1], :width => 18
pdf.text_box card.task2, :size => 8, :align => :left, :at => [12+18, 125-10*1], :width => cell.width-18
pdf.text_box card.task3status, :size => 8, :align => :left, :at => [12, 125-10*2], :width => 18
pdf.text_box card.task3, :size => 8, :align => :left, :at => [12+18, 125-10*2], :width => cell.width-18
pdf.text_box card.task4status, :size => 8, :align => :left, :at => [12, 125-10*3], :width => 18
pdf.text_box card.task4, :size => 8, :align => :left, :at => [12+18, 125-10*3], :width => cell.width-18
pdf.text_box card.task5status, :size => 8, :align => :left, :at => [12, 125-10*4], :width => 18
pdf.text_box card.task5, :size => 8, :align => :left, :at => [12+18, 125-10*4], :width => cell.width-18
pdf.text_box card.task6status, :size => 8, :align => :left, :at => [12, 125-10*5], :width => 18
pdf.text_box card.task6, :size => 8, :align => :left, :at => [12+18, 125-10*5], :width => cell.width-18
pdf.text_box card.task7status, :size => 8, :align => :left, :at => [12, 125-10*6], :width => 18
pdf.text_box card.task7, :size => 8, :align => :left, :at => [12+18, 125-10*6], :width => cell.width-18
# metadata
pdf.fill_color "999999"
pdf.text_box card.labels, :size => 8, :align => :right, :at => [12, 82], :width => cell.width-18
pdf.text_box card.state.capitalize, :size => 8, :align => :right, :at => [12, 50], :width => cell.width-18
pdf.text_box card.type.capitalize, :size => 8, :align => :right, :at => [12, 18], :width => cell.width-18
pdf.fill_color "000000"
end
end
# --- Footer
# pdf.number_pages "#{outfile}.pdf", [pdf.bounds.left, -28]
# pdf.number_pages "<page>/<total>", [pdf.bounds.right-16, -28]
end
puts ">>> Generated PDF file in '#{outfile}.pdf' with #{cards.size} stories:".black.on_green
cards.each do |card|
puts "* #{card.title}"
end
rescue Exception
puts "[!] There was an error while generating the PDF file... What happened was:".white.on_red
raise
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment