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



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

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



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

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



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

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



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

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



102
103
104
105
# File 'lib/guides_style_18f/navigation.rb', line 102

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


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

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



62
63
64
65
66
# File 'lib/guides_style_18f/navigation.rb', line 62

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



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

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



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

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



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

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