Planet of the Crabs
🦀 fearless rust


Resume Build System

Posted on by Rust — Jim Turner

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

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

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.