I developed a system to parse my resume from YAML-formatted data files and use templates to generate PDF, HTML, plain text, Sphinx, and Markdown output. I track all of my data files and templates in Git, which allows me to easily keep track of changes over time, tag versions customized for specific applications, etc. It is partly inspired by Ming-Ho Yee’s resume project. You can view the public portions of the project source code on its GitHub page, and you can view generated copies of my resume.
Motivation
For a long time, I maintained my resume in Microsoft Word, but that was a pain because
Much of the formatting information was hidden in the WYSIWYG interface, which made debugging formatting problems very frustrating, particularly on something like a resume where precise formatting is important. I used Word’s support for styles, tab stops, etc., and I am very familiar with Word, but it’s just a frustrating and buggy program.
Word does not support Linux, so when I switched from Windows to Linux, I had to use Word in a Windows virtual machine. I tried using LibreOffice before switching to my current approach, but LibreOffice has most of Word’s other problems.
There was no good way to track my changes, view differences between versions, etc., due to Word’s binary format. Of course, Word has built-in reviewing and diffing functionality, but it’s designed for reviewing documents, not long-term history tracking, and it doesn’t integrate nicely with Git.
There was no good way to produce other file formats (except PDF), which were necessary for some job applications and my personal website.
Now, I have complete control of formatting without it being hidden behind a GUI, I can build my resume on Linux, I can use Git for version control with understandable diffs, and I can easily produce whatever file format I need.
How it Works
A Python script takes as arguments the desired output format, the template to use, the output filename, and the source data file(s). It uses the PyYAML library to parse the YAML-formatted data file(s) into an in-memory data structure. If multiple data files are provided, the script merges the data together, which allows e.g. for separation between data to be published online and data to be included only on hard copies (such as an address or phone number).
Next, the script parses the section of the YAML-formatted configuration file corresponding to the desired output format. This includes
replacements to be applied to the raw data strings for escaping problematic characters (e.g. replacing
&
with&
in HTML), applying simple markup (e.g.//emphasis//
for emphasis), etc.the delimiters to be used by the template system (because the default Jinja2 delimiters don’t work well with LaTeX)
the desired line endings for the output file (generally
\n
, but\r\n
for the plain text file for MS Notepad users)
Finally, the script applies the replacements to the raw data strings and then uses Jinja2 to fill the data into the template. The script provides some custom filters to use in the templates for line wrapping, alignment, etc.
A Makefile provides instructions to build individual files or just rebuild
all of them, so a simple call to make
builds everything at once.
Input Files
This is a portion of a resume data file. It illustrates the YAML-formatted data
structure and some of the markup specified in the configuration file. For
example, --
is used to represent en dashes in date ranges, ~
is used to
represent non-breaking spaces, and //emphasis//
is used to emphasize award
names.
summary:
Mechanical engineering Ph.D.~student with research and industry experience in
reinforcement learning, nonlinear dynamical systems, mechanical simulation,
electromechanical controls, product development, testing and verification,
data analysis, and software development.
education:
- degree: Ph.D.~Mechanical Engineering
university: Duke University
location: Durham,~NC
grade: 4.00~GPA
date: 2015--present
multicols: 2
description:
- "//2017 National Defense Science and Engineering Graduate (NDSEG) Fellowship:// Merit-based, national, full-ride fellowship"
- "//2015 James~B.~Duke Fellowship:// Merit-based, four-year fellowship"
- "//2015 Pratt/Gardner Fellowship:// Merit-based fellowship"
- degree: B.S.~Mechanical Engineering
university: North Carolina State University
location: Raleigh,~NC
grade: Valedictorian, 4.00~GPA
date: 2011--2015
multicols: 2
description:
- "//Minors:// Spanish & Computer Programming"
- "//2015 NCSU Mech.~& Aero.~Engineering Senior Award for Leadership//"
- "//2014 Goldwater Scholar:// Merit-based, national scholarship"
- "//2011 NCSU Park Scholar:// Merit-based, full-ride scholarship"
This is a portion of a configuration file for LaTeX output:
latex:
replacements:
- ['&', '\\&']
- ['%', '\\%']
- ['\$', '\\$']
- ['LaTeX', '\\LaTeX']
- ['//(.*?)//', '\\emph{\1}']
jinja2_delim: ['%<', '>%', '<<', '>>', '%%<', '>%%']
line_endings: "\n"
This is a portion of a template for plain text output. It illustrates some of the features of the Jinja2 templating language, including filters, conditionals, and loops.
{{ "#" * (contact.name.first + " " + contact.name.last)|length }}
{{ contact.name.first }} {{ contact.name.last }}
{{ "#" * (contact.name.first + " " + contact.name.last)|length }}
{% if contact.address is defined and contact.address.street is defined and contact.address.city is defined %}
Address: {{ contact.address.street }} – {{ contact.address.city }}
{% elif contact.address is defined and contact.address.city is defined %}
Address: {{ contact.address.city }}
{% endif %}
{% if contact.address is defined and contact.address.country is defined %}
{{ contact.address.country }}
{% endif %}
{% if contact.phone is defined %}
Phone: {{ contact.phone }}
{% endif %}
{% if contact.email is defined %}
Email: {{ contact.email }}
{% endif %}
{% if contact.linkedin is defined %}
Social: linkedin.com/in/{{ contact.linkedin }}
{% endif %}
{% if contact.web is defined %}
Web: {{ contact.web }}
{% endif %}
Summary
=======
{{ summary|hard_wrap(WIDTH) }}
Education
=========
{{ entrylist(education) }}
Publications & Presentations
============================
{% for item in publications %}
{{ item.text|hard_wrap(WIDTH,0,"",2) }}
{% endfor %}
More Information
If you’d like to see the specifics of usage, dependencies, license, etc., see the GitHub page. The project is published under fairly open licenses, so you can adapt it for your own use.
You can view the Markdown output for my resume integrated into this site, or you can download my resume as PDF or my resume as plain text.