Skip to content

Commit

Permalink
Ensure YAML is free of duplicate keys. (#15)
Browse files Browse the repository at this point in the history
* Ensure YAML is free of duplicate keys.
* Refines one validation
* Fixes shebangs so Ruby version works correctly despite system ruby being installed
* Add Handbook glossary, and de-dupe entries. Fixes #10 and #12
  • Loading branch information
beechnut authored Feb 2, 2022
1 parent e652266 commit a387d20
Show file tree
Hide file tree
Showing 7 changed files with 1,394 additions and 649 deletions.
2 changes: 1 addition & 1 deletion bin/build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#! /usr/bin/ruby
#!/usr/bin/env ruby
require_relative '../lib/markdownify'

Markdownify.new(*ARGV).perform
2 changes: 1 addition & 1 deletion bin/validate
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#! /usr/bin/ruby
#!/usr/bin/env ruby
require_relative '../lib/validate'

GlossaryValidator.new(path: ARGV[0]).perform
603 changes: 301 additions & 302 deletions glossary.md

Large diffs are not rendered by default.

1,350 changes: 1,009 additions & 341 deletions glossary.yml

Large diffs are not rendered by default.

55 changes: 52 additions & 3 deletions lib/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class GlossaryValidator

include Common

attr_reader :data, :key
attr_reader :data, :key, :path

# @param path [String | nil] path to glossary file
def initialize(path: nil)
Expand All @@ -25,10 +25,30 @@ def initialize(path: nil)
# Validate all entries
def perform
validator = EntryValidator.new(data[key])
report_duplicate_keys
data[key].each do |entry|
validator.validate([entry].to_h)
end
ensure
display_reminders(validator)
end

def report_duplicate_keys
file = File.read(path)
keys = file.scan(/^\s{2}(\S{1}.*):$/).flatten
keys.tally.detect do |k, count|
case count
when 0 then
# NO OP
when 1
# NO OP
else
raise DuplicateKeyError.new(k, count)
end
end
end

def display_reminders(validator)
# Regardless of errors, show the reminders
if validator.reminders.any?
puts "\nReminders:"
Expand All @@ -37,10 +57,11 @@ def perform
puts "\n"
end
end

end




# Validates an entry. Needs the entire glossary file to work,
# as it needs to determine whether linked terms are present.
class EntryValidator
Expand Down Expand Up @@ -139,8 +160,13 @@ def validate_acronym(acronym_data)
raise TermNotFoundError.new(key, term)
end

unless context[term.to_sym][:type] == "term"
case context[term.to_sym][:type]
when "acronym" then
raise AcronymReferenceError.new(key, term)
when "term" then
# NO OP
else
raise EntryTypeError.new(term)
end
end

Expand Down Expand Up @@ -168,6 +194,29 @@ def assert_no_extra_keys(key, value_set, only_allow=[])

end


class DuplicateKeyError < StandardError
attr_reader :key, :count

def initialize(key, count)
@key = key
@count = count
super(message)
end

def message
<<~ERR
I found #{count} entries for "#{key}".
How can I know which one to use?
Please delete or combine until there is only one entry for "#{key}".
ERR
end
end

class MissingTermError < StandardError
attr_reader :key, :term

Expand Down
13 changes: 13 additions & 0 deletions test/test_glossary_dupe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
entries:

FEMA:
type: acronym
term: Federal Emergency Management Agency

Federal Emergency Management Agency:
type: term
description: null

FEMA:
type: acronym
term: Federal Emergency Management Agency
18 changes: 17 additions & 1 deletion test/validate_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,25 @@

include Fixtures

describe GlossaryValidator do
describe "with a valid glossary" do
it "raises no errors" do
subject = GlossaryValidator.new(path: './test/test_glossary.yml')
assert subject.perform
end
end

describe "with a glossary containing duplicate entries" do
it "raises an error" do
subject = GlossaryValidator.new(path: './test/test_glossary_dupe.yml')
assert_raises (DuplicateKeyError) { subject.perform }
end
end
end

describe EntryValidator do
describe "with a malformed entry" do
it "is errors" do
it "errors" do
subject = EntryValidator.new({})
assert_raises (ArgumentError) { subject.validate({a: 1, b: 2}) }
end
Expand Down

0 comments on commit a387d20

Please sign in to comment.