gov_codes 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +15 -1
  3. data/.tool-versions +1 -1
  4. data/CHANGELOG.md +57 -2
  5. data/README.md +223 -22
  6. data/Rakefile +7 -1
  7. data/checksums/gov_codes-0.1.0.gem.sha512 +1 -0
  8. data/checksums/gov_codes-0.1.1.gem.sha512 +1 -0
  9. data/lib/gov_codes/afsc/enlisted.rb +134 -24
  10. data/lib/gov_codes/afsc/officer.rb +141 -25
  11. data/lib/gov_codes/afsc/releases/dafecd/2025-10-31/enlisted.yml +2726 -0
  12. data/lib/gov_codes/afsc/releases/dafecd/2025-10-31/ri.yml +369 -0
  13. data/lib/gov_codes/afsc/releases/dafocd/2025-10-31/officer.yml +2393 -0
  14. data/lib/gov_codes/afsc/releases/dafocd/2025-10-31/ri.yml +193 -0
  15. data/lib/gov_codes/afsc/releases.rb +219 -0
  16. data/lib/gov_codes/afsc/releases.yml +11 -0
  17. data/lib/gov_codes/afsc/ri.rb +207 -0
  18. data/lib/gov_codes/afsc.rb +35 -3
  19. data/lib/gov_codes/dafecd/index_builder.rb +416 -0
  20. data/lib/gov_codes/dafecd/patterns.rb +50 -0
  21. data/lib/gov_codes/dafecd/publication.rb +252 -0
  22. data/lib/gov_codes/dafecd/record_splitter.rb +77 -0
  23. data/lib/gov_codes/dafecd/ri_sdi/change_date.rb +63 -0
  24. data/lib/gov_codes/dafecd/ri_sdi/config.rb +137 -0
  25. data/lib/gov_codes/dafecd/ri_sdi/index_builder.rb +265 -0
  26. data/lib/gov_codes/dafecd/ri_sdi/ri_list_parser.rb +125 -0
  27. data/lib/gov_codes/dafecd/ri_sdi/sdi_card_parser.rb +151 -0
  28. data/lib/gov_codes/dafecd/ri_sdi/sdi_section_splitter.rb +77 -0
  29. data/lib/gov_codes/dafecd/ri_sdi/section_slicer.rb +45 -0
  30. data/lib/gov_codes/dafecd/ri_sdi/title.rb +76 -0
  31. data/lib/gov_codes/dafecd/ri_sdi/title_overrides/dafecd.yml +124 -0
  32. data/lib/gov_codes/dafecd/ri_sdi/title_overrides/dafocd.yml +78 -0
  33. data/lib/gov_codes/dafecd/shredout_acronyms.rb +47 -0
  34. data/lib/gov_codes/dafecd/shredout_degluer.rb +73 -0
  35. data/lib/gov_codes/dafecd/shredout_overrides/dafecd.yml +27 -0
  36. data/lib/gov_codes/dafecd/shredout_overrides/dafocd.yml +27 -0
  37. data/lib/gov_codes/dafecd/shredout_parser.rb +75 -0
  38. data/lib/gov_codes/dafecd/specialty_parser.rb +200 -0
  39. data/lib/gov_codes/dafecd/text.rb +48 -0
  40. data/lib/gov_codes/dafecd/title_degluer.rb +67 -0
  41. data/lib/gov_codes/dafecd/title_overrides/dafocd.yml +141 -0
  42. data/lib/gov_codes/dafecd/title_overrides.yml +142 -0
  43. data/lib/gov_codes/data_loader.rb +49 -36
  44. data/lib/gov_codes/version.rb +1 -1
  45. metadata +36 -4
  46. data/lib/gov_codes/afsc/enlisted.yml +0 -725
@@ -11,65 +11,78 @@ module GovCodes
11
11
 
12
12
  def data(lookup: $LOAD_PATH)
13
13
  data = {}
14
+ lookup_array = Array(lookup)
15
+ return data if lookup_array.empty?
14
16
 
15
- namespace_parts = name.split("::")
16
- .map { |it| it.gsub(/([A-Z])([a-z])/, '_\1\2').downcase }
17
- .map { |it| it.sub(/^_/, "") }
17
+ # Add the gem's lib directory to the lookup path
18
+ gem_lib_dir = File.expand_path("..", __dir__)
19
+ lookup_paths = [gem_lib_dir] + lookup_array
18
20
 
19
- # Append .yml to the last item
21
+ # Convert namespace to file path parts (e.g., "GovCodes::AFSC::Enlisted" -> ["gov_codes", "afsc", "enlisted.yml"])
22
+ namespace_parts = name.split("::")
23
+ .map { |part| part.gsub(/([A-Z])([a-z])/, '_\1\2').downcase.sub(/^_/, "") }
20
24
  namespace_parts[-1] = "#{namespace_parts[-1]}.yml"
21
25
 
22
- # Iterate through each path in the lookup array
23
- files = lookup.map do |dir|
26
+ # Find all existing YAML files in lookup paths
27
+ lookup_paths.filter_map do |dir|
24
28
  yaml_path = File.join(dir, *namespace_parts)
25
29
  yaml_path if File.exist?(yaml_path)
26
- end
27
- .compact
28
- .uniq
29
- files.each do |path|
30
- data.merge!(YAML.load_file(path, symbolize_names: true))
30
+ end.uniq.each do |path|
31
+ yaml_data = YAML.load_file(path, symbolize_names: true)
32
+ data.merge!(yaml_data) if yaml_data.is_a?(Hash)
33
+ rescue Psych::SyntaxError, TypeError
34
+ # Handle invalid YAML gracefully
35
+ next
31
36
  end
32
37
 
33
38
  data
34
39
  end
35
40
 
36
41
  def reset_data(lookup: $LOAD_PATH)
37
- remove_const(:DATA)
42
+ remove_const(:DATA) if const_defined?(:DATA, false)
38
43
  const_set(:DATA, data(lookup:).freeze)
39
- remove_const(:CODES)
44
+ remove_const(:CODES) if const_defined?(:CODES, false)
40
45
  const_set(:CODES, {})
41
46
  end
42
47
 
48
+ # Load and merge a flat overlay YAML map (e.g. a consumer acronyms overlay)
49
+ # named +basename+ under gov_codes/afsc across the load path. Files loaded
50
+ # later win, so a consumer file merges over any shipped one. Returns {} when
51
+ # none exist; malformed files are skipped (graceful degradation).
52
+ def flat_overlay(basename, lookup: $LOAD_PATH)
53
+ merged = {}
54
+ gem_lib_dir = File.expand_path("..", __dir__)
55
+ ([gem_lib_dir] + Array(lookup)).uniq.each do |dir|
56
+ path = File.join(dir, "gov_codes", "afsc", basename)
57
+ next unless File.exist?(path)
58
+
59
+ overlay = YAML.load_file(path, symbolize_names: true)
60
+ merged.merge!(overlay) if overlay.is_a?(Hash)
61
+ rescue Psych::SyntaxError, TypeError
62
+ next
63
+ end
64
+ merged
65
+ end
66
+
43
67
  def find_name_recursive(result)
44
- # Start with the career field (e.g., "1N")
45
68
  base_code = result[:career_field].to_sym
69
+ base_data = self::DATA[base_code]
70
+ return "Unknown" unless base_data
46
71
 
47
- loaded_data = self::DATA
48
- # Look up in the codes hash
49
- if loaded_data[base_code]
50
- # If we have a subcategory, try to find a more specific name
51
- if result[:subcategory] &&
52
- loaded_data.dig(base_code, :subcategories) &&
53
- loaded_data.dig(base_code, :subcategories, result[:subcategory])
54
-
55
- subdivision = loaded_data.dig(base_code, :subcategories, result[:subcategory])
56
- # If we have a shredout, try to find an even more specific name
57
- if result[:shredout] &&
58
- subdivision.dig(:subcategories) &&
59
- subdivision.dig(:subcategories, result[:shredout])
60
- return subdivision.dig(:subcategories, result[:shredout], :name)
72
+ # Try subcategory lookup if present
73
+ if result[:subcategory]
74
+ subdivision = base_data.dig(:subcategories, result[:subcategory])
75
+ if subdivision
76
+ # Try shredout lookup if present
77
+ if result[:shredout]
78
+ shredout_name = subdivision.dig(:subcategories, result[:shredout], :name)
79
+ return shredout_name if shredout_name
61
80
  end
62
-
63
- # Return the subdivision name if no shredout match
64
- return subdivision.dig(:name)
81
+ return subdivision[:name] if subdivision[:name]
65
82
  end
66
-
67
- # Return the base name if no subdivision match
68
- return loaded_data.dig(base_code, :name)
69
83
  end
70
84
 
71
- # Return a default if no match found
72
- "Unknown"
85
+ base_data[:name] || "Unknown"
73
86
  end
74
87
  end
75
88
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GovCodes
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gov_codes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
@@ -22,11 +22,43 @@ files:
22
22
  - CHANGELOG.md
23
23
  - README.md
24
24
  - Rakefile
25
+ - checksums/gov_codes-0.1.0.gem.sha512
26
+ - checksums/gov_codes-0.1.1.gem.sha512
25
27
  - lib/gov_codes.rb
26
28
  - lib/gov_codes/afsc.rb
27
29
  - lib/gov_codes/afsc/enlisted.rb
28
- - lib/gov_codes/afsc/enlisted.yml
29
30
  - lib/gov_codes/afsc/officer.rb
31
+ - lib/gov_codes/afsc/releases.rb
32
+ - lib/gov_codes/afsc/releases.yml
33
+ - lib/gov_codes/afsc/releases/dafecd/2025-10-31/enlisted.yml
34
+ - lib/gov_codes/afsc/releases/dafecd/2025-10-31/ri.yml
35
+ - lib/gov_codes/afsc/releases/dafocd/2025-10-31/officer.yml
36
+ - lib/gov_codes/afsc/releases/dafocd/2025-10-31/ri.yml
37
+ - lib/gov_codes/afsc/ri.rb
38
+ - lib/gov_codes/dafecd/index_builder.rb
39
+ - lib/gov_codes/dafecd/patterns.rb
40
+ - lib/gov_codes/dafecd/publication.rb
41
+ - lib/gov_codes/dafecd/record_splitter.rb
42
+ - lib/gov_codes/dafecd/ri_sdi/change_date.rb
43
+ - lib/gov_codes/dafecd/ri_sdi/config.rb
44
+ - lib/gov_codes/dafecd/ri_sdi/index_builder.rb
45
+ - lib/gov_codes/dafecd/ri_sdi/ri_list_parser.rb
46
+ - lib/gov_codes/dafecd/ri_sdi/sdi_card_parser.rb
47
+ - lib/gov_codes/dafecd/ri_sdi/sdi_section_splitter.rb
48
+ - lib/gov_codes/dafecd/ri_sdi/section_slicer.rb
49
+ - lib/gov_codes/dafecd/ri_sdi/title.rb
50
+ - lib/gov_codes/dafecd/ri_sdi/title_overrides/dafecd.yml
51
+ - lib/gov_codes/dafecd/ri_sdi/title_overrides/dafocd.yml
52
+ - lib/gov_codes/dafecd/shredout_acronyms.rb
53
+ - lib/gov_codes/dafecd/shredout_degluer.rb
54
+ - lib/gov_codes/dafecd/shredout_overrides/dafecd.yml
55
+ - lib/gov_codes/dafecd/shredout_overrides/dafocd.yml
56
+ - lib/gov_codes/dafecd/shredout_parser.rb
57
+ - lib/gov_codes/dafecd/specialty_parser.rb
58
+ - lib/gov_codes/dafecd/text.rb
59
+ - lib/gov_codes/dafecd/title_degluer.rb
60
+ - lib/gov_codes/dafecd/title_overrides.yml
61
+ - lib/gov_codes/dafecd/title_overrides/dafocd.yml
30
62
  - lib/gov_codes/data_loader.rb
31
63
  - lib/gov_codes/version.rb
32
64
  - sig/gov_codes.rbs
@@ -43,14 +75,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
43
75
  requirements:
44
76
  - - ">="
45
77
  - !ruby/object:Gem::Version
46
- version: 3.1.0
78
+ version: 3.2.0
47
79
  required_rubygems_version: !ruby/object:Gem::Requirement
48
80
  requirements:
49
81
  - - ">="
50
82
  - !ruby/object:Gem::Version
51
83
  version: '0'
52
84
  requirements: []
53
- rubygems_version: 3.6.7
85
+ rubygems_version: 4.0.10
54
86
  specification_version: 4
55
87
  summary: Handle codes used by the US government.
56
88
  test_files: []