Module: GovCodes::AFSC::RI

Defined in:
lib/gov_codes/afsc/ri.rb

Overview

Reporting Identifiers (RI) and Special Duty Identifiers (SDI), resolved against the versioned classification-directory release indexes. RI/SDI codes live in BOTH directories under two different code grammars:

Enlisted (DAFECD), 5-char:  \d[A-Z]\d{3}[A-Z]?   e.g. 9Z200, 8R300A
Officer  (DAFOCD), 4-char:  \d{2}[A-Z]\d[A-Z]?   e.g. 90G0,  92T1

A single find entry point dispatches by shape to the matching publication's ri.yml index (Releases.ri_index). Entries share the shape of enlisted/officer specialty records (:name, :acronym, :shredouts, :shredout_acronyms), so shredout suffixes and acronyms resolve exactly as they do for Enlisted/Officer.

Defined Under Namespace

Classes: Code, Parser

Class Method Summary collapse

Class Method Details

.find(code, as_of: nil) ⇒ Object

Resolve an RI/SDI code against the release in effect on as_of (default: today). Dispatches by code shape to the enlisted (DAFECD) or officer (DAFOCD) ri.yml index. Returns nil when the code parses as neither shape, when the resolved index lacks the code, or when as_of precedes the earliest shipped release for the relevant publication.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/gov_codes/afsc/ri.rb', line 115

def self.find(code, as_of: nil)
  code = code.to_s
  parsed = Parser.new(code).parse
  publication = parsed[:publication]
  return nil unless publication

  # Key the memo on the RESOLVED release date so equivalent as_of values
  # (nil, the Date, its string form) share one slot.
  effective_date = Releases.effective_date_for(as_of: as_of, publication: publication)
  CODES[[code, effective_date]] ||= begin
    index = Releases.ri_index(as_of: as_of, publication: publication)
    entry = index[parsed[:specific_ri]]
    return nil unless entry

    suffix = parsed[:suffix]
    # Shredout suffix meaning, only when the directory documents it.
    shredout_name = suffix && entry.dig(:shredouts, suffix)
    name = shredout_name || entry[:name]
    return nil if name.nil?

    # A documented shredout acronym wins for a shredded code; otherwise the
    # entry's own acronym (which a consumer overlay may set).
    shredout_acronym = suffix && entry.dig(:shredout_acronyms, suffix)

    Code.new(
      career_group: parsed[:career_group],
      career_field: parsed[:career_field],
      identifier: parsed[:identifier],
      suffix: suffix,
      specific_ri: parsed[:specific_ri],
      name: name,
      acronym: shredout_acronym || entry[:acronym],
      effective_date: effective_date
    )
  end
end

.find_by_acronym(acronym, as_of: nil) ⇒ Object

Resolve the RI/SDI code whose acronym matches acronym (case-insensitive) in the release in effect on as_of. Scans the enlisted index first, then the officer index; within an entry the entry's own acronym is tried before its shredout acronyms (a shredout match returns the concrete shredded code). First match wins. Returns nil when no acronym in the resolved release(s) matches (no leakage across document dates).



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/gov_codes/afsc/ri.rb', line 158

def self.find_by_acronym(acronym, as_of: nil)
  acronym = acronym.to_s.upcase
  return nil if acronym.empty?

  [Releases::ENLISTED_PUBLICATION, Releases::OFFICER_PUBLICATION].each do |publication|
    index = Releases.ri_index(as_of: as_of, publication: publication)
    index.each do |code, entry|
      return find(code.to_s, as_of: as_of) if entry[:acronym].to_s.upcase == acronym

      (entry[:shredout_acronyms] || {}).each do |suffix, acr|
        return find("#{code}#{suffix}", as_of: as_of) if acr.to_s.upcase == acronym
      end
    end
  end
  nil
end

.reset_data(lookup: $LOAD_PATH) ⇒ Object

Clears the memoized lookups and resets the versioned release loader. The lookup keyword is accepted for interface parity with Enlisted/Officer; the versioned index is resolved from the load path at lookup time.



201
202
203
204
# File 'lib/gov_codes/afsc/ri.rb', line 201

def self.reset_data(lookup: $LOAD_PATH)
  Releases.reset!
  CODES.clear
end

.search(prefix, as_of: nil) ⇒ Object

Walk both publications' RI/SDI indexes for the release in effect on as_of, emitting each base code and its shredout-suffixed combinations, and return the Codes whose code starts with prefix.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/gov_codes/afsc/ri.rb', line 178

def self.search(prefix, as_of: nil)
  prefix = prefix.to_s.upcase

  codes = []
  [Releases::ENLISTED_PUBLICATION, Releases::OFFICER_PUBLICATION].each do |publication|
    index = Releases.ri_index(as_of: as_of, publication: publication)
    index.each do |code, entry|
      code_str = code.to_s
      codes << code_str
      (entry[:shredouts] || {}).each_key do |suffix|
        codes << "#{code_str}#{suffix}"
      end
    end
  end

  codes.select { |code| code.start_with?(prefix) }
    .map { |code| find(code, as_of: as_of) }
    .compact
end