Module: GuidesStyle18F::FrontMatter

Defined in:
lib/guides_style_18f/navigation.rb

Constant Summary collapse

EXTNAMES =
%w(.md .html)

Class Method Summary collapse

Class Method Details

.adjust_config_paths(basedir, config) ⇒ Object



52
53
54
55
56
57
58
# File 'lib/guides_style_18f/navigation.rb', line 52

def self.adjust_config_paths(basedir, config)
  source = config['source']
  config['source'] = source.nil? ? basedir : File.join(basedir, source)
  destination = config['destination']
  destination = '_site' if destination.nil?
  config['destination'] = File.join(basedir, destination)
end

.init_file_to_front_matter_map(basedir) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/guides_style_18f/navigation.rb', line 87

def self.init_file_to_front_matter_map(basedir)
  file_to_front_matter = {}
  Dir.chdir(basedir) do
    pages_dir = Dir.exist?('_pages') ? '_pages' : 'pages'
    Dir[File.join(pages_dir, '**', '*')].each do |file_name|
      extname = File.extname(file_name)
      next unless File.file?(file_name) && EXTNAMES.include?(extname)
      file_to_front_matter[file_name] = nil
    end
  end
  file_to_front_matter
end

.init_site(basedir) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/guides_style_18f/navigation.rb', line 41

def self.init_site(basedir)
  Dir.chdir(basedir) do
    config = SafeYAML.load_file('_config.yml', safe: true)
    adjust_config_paths(basedir, config)
    site = Jekyll::Site.new(Jekyll.configuration(config))
    site.reset
    site.read
    site
  end
end

.load(basedir) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/guides_style_18f/navigation.rb', line 10

def self.load(basedir)
  # init_file_to_front_matter_map is initializing the map with a nil value
  # for every file that _should_ contain front matter as far as the
  # navigation menu is concerned. Any nil values that remain after merging
  # with the site_file_to_front_matter map will result in a validation
  # error.
  init_file_to_front_matter_map(basedir).merge(
    site_file_to_front_matter(init_site(basedir)))
end

.missing_property_errors(data) ⇒ Object



100
101
102
103
# File 'lib/guides_style_18f/navigation.rb', line 100

def self.missing_property_errors(data)
  properties = %w(title permalink)
  properties.map { |p| "no `#{p}:` property" unless data[p] }.compact
end


105
106
107
108
109
110
111
112
# File 'lib/guides_style_18f/navigation.rb', line 105

def self.permalink_errors(data)
  pl = data['permalink']
  return [] if pl.nil?
  errors = []
  errors << "`permalink:` does not begin with '/'" unless pl.start_with? '/'
  errors << "`permalink:` does not end with '/'" unless pl.end_with? '/'
  errors
end

.site_file_to_front_matter(site) ⇒ Object



60
61
62
63
64
# File 'lib/guides_style_18f/navigation.rb', line 60

def self.site_file_to_front_matter(site)
  site_pages(site).map do |page|
    [page.relative_path,  page.data]
  end.to_h
end

.site_pages(site) ⇒ Object

We’re supporting two possible configurations:

  • a ‘pages/` directory in which documents appear as part of the regular site.pages collection; we have to filter by page.relative_path, and we do not assign a permalink so that validation (in a later step) will ensure that each page has a permalink assigned

  • an actual ‘pages` collection, stored in a `_pages` directory; no filtering is necessary, and we can reliably set the permalink to page.url as a default



76
77
78
79
80
81
82
83
84
85
# File 'lib/guides_style_18f/navigation.rb', line 76

def self.site_pages(site)
  pages = site.collections['pages']
  if pages.nil?
    site.pages.select do |page|
      page.relative_path.start_with?('/pages') || page.url == '/'
    end
  else
    pages.docs.each { |page| page.data['permalink'] ||= page.url }
  end
end

.validate(front_matter) ⇒ Object



31
32
33
34
35
36
37
# File 'lib/guides_style_18f/navigation.rb', line 31

def self.validate(front_matter)
  front_matter.map do |file, data|
    next [file, ['no front matter defined']] if data.nil?
    errors = missing_property_errors(data) + permalink_errors(data)
    [file, errors] unless errors.empty?
  end.compact.to_h
end

.validate_with_message_upon_error(front_matter) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/guides_style_18f/navigation.rb', line 20

def self.validate_with_message_upon_error(front_matter)
  files_with_errors = validate front_matter
  return if files_with_errors.empty?
  message = ['The following files have errors in their front matter:']
  files_with_errors.each do |file, errors|
    message << "  #{file}:"
    message.concat errors.map { |error| "    #{error}" }
  end
  message.join "\n" unless message.size == 1
end