gov_codes 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/.simplecov +3 -1
- data/CHANGELOG.md +52 -2
- data/README.md +50 -4
- data/Rakefile +1 -0
- data/checksums/gov_codes-0.1.0.gem.sha512 +1 -0
- data/lib/gov_codes/afsc/enlisted.rb +92 -13
- data/lib/gov_codes/afsc/enlisted.yml +532 -725
- data/lib/gov_codes/afsc/officer.rb +73 -13
- data/lib/gov_codes/afsc/officer.yml +1072 -0
- data/lib/gov_codes/afsc/ri.rb +172 -0
- data/lib/gov_codes/afsc/ri.yml +237 -0
- data/lib/gov_codes/afsc.rb +12 -1
- data/lib/gov_codes/data_loader.rb +30 -36
- data/lib/gov_codes/version.rb +1 -1
- metadata +6 -2
|
@@ -17,7 +17,8 @@ module GovCodes
|
|
|
17
17
|
career_group: nil,
|
|
18
18
|
functional_area: nil,
|
|
19
19
|
qualification_level: nil,
|
|
20
|
-
shredout: nil
|
|
20
|
+
shredout: nil,
|
|
21
|
+
specific_afsc: nil
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
# Scan for prefix (optional)
|
|
@@ -26,20 +27,24 @@ module GovCodes
|
|
|
26
27
|
# Scan for career group (two digits)
|
|
27
28
|
career_group = scanner.scan(/\d{2}/)
|
|
28
29
|
return result unless career_group
|
|
29
|
-
result[:career_group] = career_group
|
|
30
|
+
result[:career_group] = career_group.to_sym
|
|
30
31
|
|
|
31
32
|
# Scan for functional area (uppercase letter)
|
|
32
33
|
functional_area = scanner.scan(/[A-Z]/)
|
|
33
34
|
return result unless functional_area
|
|
34
|
-
result[:functional_area] = functional_area
|
|
35
|
+
result[:functional_area] = functional_area.to_sym
|
|
35
36
|
|
|
36
|
-
# Scan for qualification level (digit 0-4)
|
|
37
|
-
qualification_level = scanner.scan(/[0-
|
|
37
|
+
# Scan for qualification level (digit 0-4 or letter X-Z)
|
|
38
|
+
qualification_level = scanner.scan(/[0-4A-Z]/)
|
|
38
39
|
return result unless qualification_level
|
|
39
|
-
result[:qualification_level] = qualification_level
|
|
40
|
+
result[:qualification_level] = qualification_level.to_sym
|
|
41
|
+
|
|
42
|
+
# Build specific AFSC
|
|
43
|
+
result[:specific_afsc] = :"#{result[:career_group]}#{result[:functional_area]}#{result[:qualification_level]}"
|
|
40
44
|
|
|
41
45
|
# Scan for shredout (optional)
|
|
42
|
-
|
|
46
|
+
shredout = scanner.scan(/[A-Z]/)
|
|
47
|
+
result[:shredout] = shredout&.to_sym
|
|
43
48
|
|
|
44
49
|
# Check if we've reached the end of the string
|
|
45
50
|
return result unless scanner.eos?
|
|
@@ -49,6 +54,7 @@ module GovCodes
|
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
extend GovCodes::DataLoader
|
|
57
|
+
|
|
52
58
|
DATA = data
|
|
53
59
|
|
|
54
60
|
Code = Data.define(
|
|
@@ -57,9 +63,40 @@ module GovCodes
|
|
|
57
63
|
:functional_area,
|
|
58
64
|
:qualification_level,
|
|
59
65
|
:shredout,
|
|
66
|
+
:specific_afsc,
|
|
60
67
|
:name
|
|
61
68
|
)
|
|
62
69
|
|
|
70
|
+
def self.find_name_recursive(result)
|
|
71
|
+
name = nil
|
|
72
|
+
data = DATA
|
|
73
|
+
|
|
74
|
+
# For officer codes, build the lookup key from career group + functional area + qual level
|
|
75
|
+
# like "11BX" where "11" is career group, "B" is functional area, "X" is qual level
|
|
76
|
+
career_group = result[:career_group].to_s
|
|
77
|
+
functional_area = result[:functional_area].to_s
|
|
78
|
+
qual_level = result[:qualification_level].to_s
|
|
79
|
+
combined_key = :"#{career_group}#{functional_area}#{qual_level}"
|
|
80
|
+
|
|
81
|
+
# Look for the full code (e.g., "11BX", "11MX")
|
|
82
|
+
if data[combined_key]
|
|
83
|
+
name = data[combined_key][:name]
|
|
84
|
+
data = data[combined_key][:subcategories]
|
|
85
|
+
|
|
86
|
+
# Then look for shredout
|
|
87
|
+
if data && result[:shredout]
|
|
88
|
+
shred = result[:shredout]
|
|
89
|
+
# Try Symbol first (most shredouts are letters), then Integer, then String
|
|
90
|
+
lookup_value = data[shred] || data[shred.to_s.to_i] || data[shred.to_s]
|
|
91
|
+
if lookup_value
|
|
92
|
+
name = lookup_value.is_a?(Hash) ? (lookup_value[:name] || name) : (lookup_value || name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
name || "Unknown"
|
|
98
|
+
end
|
|
99
|
+
|
|
63
100
|
def self.find(code)
|
|
64
101
|
code = code.to_s
|
|
65
102
|
parser = Parser.new(code)
|
|
@@ -67,18 +104,41 @@ module GovCodes
|
|
|
67
104
|
|
|
68
105
|
return nil if result.reject { |_, v| v.nil? }.empty?
|
|
69
106
|
|
|
70
|
-
# Find the name
|
|
71
|
-
|
|
72
|
-
functional_area = result[:functional_area]
|
|
73
|
-
|
|
74
|
-
# Look up the name in the codes hash
|
|
75
|
-
name = find_name(career_group, functional_area)
|
|
107
|
+
# Find the name by recursively searching the codes hash
|
|
108
|
+
name = find_name_recursive(result)
|
|
76
109
|
|
|
77
110
|
# Add the name to the result
|
|
78
111
|
result[:name] = name
|
|
79
112
|
|
|
80
113
|
Code.new(**result)
|
|
81
114
|
end
|
|
115
|
+
|
|
116
|
+
def self.search(prefix)
|
|
117
|
+
results = []
|
|
118
|
+
prefix = prefix.to_s.upcase
|
|
119
|
+
collect_codes_recursive(DATA, "", prefix, results)
|
|
120
|
+
results.map { |code| find(code) }.compact
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def self.collect_codes_recursive(data, current_code, prefix, results)
|
|
124
|
+
return unless data.is_a?(Hash)
|
|
125
|
+
|
|
126
|
+
data.each do |key, value|
|
|
127
|
+
code = "#{current_code}#{key}"
|
|
128
|
+
|
|
129
|
+
if value.is_a?(Hash) && value[:name]
|
|
130
|
+
# This is a node with a name and possibly subcategories
|
|
131
|
+
results << code if code.start_with?(prefix)
|
|
132
|
+
collect_codes_recursive(value[:subcategories], code, prefix, results) if value[:subcategories]
|
|
133
|
+
elsif value.is_a?(String)
|
|
134
|
+
# This is a leaf node (simple string value)
|
|
135
|
+
results << code if code.start_with?(prefix)
|
|
136
|
+
elsif value.is_a?(Hash)
|
|
137
|
+
# Nested subcategories without a name at this level
|
|
138
|
+
collect_codes_recursive(value, current_code, prefix, results)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
82
142
|
end
|
|
83
143
|
end
|
|
84
144
|
end
|