YAML + Markdown is awesome.

YAML front matter is a common format used in various static site generators like Jekyll or Hugo and in tools like Obsidian.

Here's an example of a Markdown file with YAML front matter. The file below show YAML front matter is enclosed within triple-dashed lines at start of the file and includes metadata like title, date, and cost before becoming standard Markdown format.

--- 
title: "Sample Markdown File" 
date: 2024-01-11 
cost: $19.99 
--- 
# Sample Markdown File  
Welcome to this sample markdown file with YAML front matter!  

## Section 1: Introduction  
This is an example of a Markdown file that begins with a YAML 
front matter section. YAML front matter is used to hold metadata 
about the document.  

## Section 2: More Details  

The Markdown part of the file follows the front matter. It can contain various elements like text, images, links, and other formatting specific to Markdown.

Using YAML front matter attributes in code

Reading attributes:

Ruby

require 'yaml'

def extract_yaml_front_matter(file_path)
  raw_content = File.read(file_path)
  yaml_content = content.match(/---\s*\n.*?\n---/m)
  yaml_content ? YAML.load(yaml_content[0]) : nil
end

yaml_attributes = extract_yaml_front_matter("path_to_markdown_file.md")

if yaml_attributes
  puts "Title: #{yaml_attributes['title']}"
  puts "Date: #{yaml_attributes['date']}"
  puts "Cost: #{yaml_attributes['cost']}"
else
  puts "No YAML front matter found."
end

Python

import re
import yaml

def extract_yaml_front_matter(file_path):
    with open(file_path, 'r') as file:
        content = file.read()
        matches = re.search(r'^---\s*\n(.+?)\n---', content, re.DOTALL)
        if matches:
            return yaml.safe_load(matches.group(1))
        else:
            return None

# Example usage
file_path = 'path_to_your_markdown_file.md'
yaml_attributes = extract_yaml_front_matter(file_path)

if yaml_attributes:
    print("Title:", yaml_attributes.get('title'))
    print("Date:", yaml_attributes.get('date'))
    print("Cost:", yaml_attributes.get('cost'))
else:
    print("No YAML front matter found.")

Writing attributes to existing markdown

Warning

This gets a bit trickier and should be carefully thought through how to safely do this without losing any critical data where you think about it from a few angles in your use case where you consider what was written already in the markdown, both in the markdown content but also any existing YAML attributes you are add to/replacing/updating.

The basic steps to cosnider:

  1. Read the existing file:
    Open the file and read its current content.
  2. Check for Existing YAML Front Matter:
    Determine if the file already contains YAML front matter.
  3. Modify or Add YAML Front Matter: |
    If YAML front matter exists, update it.
    If not, create new YAML front matter and prepend it to the file content.
  4. Write Back to File:
    Save the modified content back to the file.

Below is a Ruby script example that demonstrates how to do this:

require 'yaml'

def read_yaml_front_matter(file_path)
  content = File.read(file_path)
  yaml_content = content.match(/---\s*\n.*?\n---/m)
  yaml_content ? YAML.load(yaml_content[0]) : {}
end

def write_yaml_front_matter(file_path, new_data)
  existing_content = File.read(file_path)
  yaml_front_matter = existing_content.match(/---\s*\n.*?\n---/m)
  
  updated_yaml = yaml_front_matter ? existing_content.sub(yaml_front_matter[0], new_data.to_yaml) : new_data.to_yaml + "\n---\n" + existing_content
  
  File.open(file_path, 'w') { |file| file.write(updated_yaml) }
end

# Example usage
file_path = 'path_to_your_markdown_file.md'
existing_data = read_yaml_front_matter(file_path)

# Add or update data
existing_data['new_key'] = 'New Value'
existing_data['title'] = 'Updated Title' # Update existing key

write_yaml_front_matter(file_path, existing_data)

puts "Updated YAML front matter in #{file_path}"