Class: Cocina::Models::Validators::DescriptionDateTimeVisitorValidator
- Inherits:
-
BaseDescriptionVisitorValidator
- Object
- BaseDescriptionVisitorValidator
- Cocina::Models::Validators::DescriptionDateTimeVisitorValidator
- Defined in:
- lib/cocina/models/validators/description_date_time_visitor_validator.rb
Overview
Validates that dates of known types are type-valid using the visitor pattern.
Constant Summary collapse
- VALIDATABLE_TYPES =
%w[edtf iso8601 w3cdtf].freeze
Instance Method Summary collapse
- #validate! ⇒ Object
-
#visit_hash(hash:, path:) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity.
Methods inherited from BaseDescriptionVisitorValidator
#path_to_s, #visit_array, #visit_obj
Instance Method Details
#validate! ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/cocina/models/validators/description_date_time_visitor_validator.rb', line 64 def validate! return if invalid_groups.empty? invalid_dates = invalid_groups.filter_map do |path, values| next if values.empty? [*values, encoding_paths[path]] end return if invalid_dates.empty? raise ValidationError, "Invalid date(s) in description: #{invalid_dates}" end |
#visit_hash(hash:, path:) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/cocina/models/validators/description_date_time_visitor_validator.rb', line 12 def visit_hash(hash:, path:) # rubocop:disable Metrics/CyclomaticComplexity # Only dates nested under a `date` key are subject to validation. # For example, event.date is in scope but event.note is not. return unless in_date_path?(path) # A hash with a validatable encoding.code "owns" the encoding for its # entire subtree. For example, the outer hash below owns iso8601 for # both structuredValue children even though those children carry no # encoding themselves: # # date: [{ # structuredValue: [ # { value: '1996', type: 'start' }, # { value: '1998', type: 'end' } # ], # encoding: { code: 'iso8601' } # ← registered at path [:date, 0] # }] # # We record the path before visiting children because # CompositeDescriptionValidator calls visit_hash on a parent before # recursing into its children, so the encoding is always registered # before any child value hashes are visited. code = hash.dig(:encoding, :code) encoding_paths[path.dup] = code if code && VALIDATABLE_TYPES.include?(code) value = hash[:value] return unless value.is_a?(String) # Resolve which encoding governs this value by finding the longest # registered encoding path that is a prefix of the current path. # Longest-prefix wins so that a more-specific inner encoding overrides # a less-specific outer one. For example, given: # # date: [{ # parallelValue: [ # { value: '1996', encoding: { code: 'edtf' } }, # path [:date,0,:parallelValue,0] # { value: '一九九六' } # path [:date,0,:parallelValue,1] # ], # encoding: { code: 'iso8601' } # path [:date,0] # }] # # The value '1996' at [:date,0,:parallelValue,0] matches both [:date,0] # (iso8601) and [:date,0,:parallelValue,0] (edtf); the longer prefix wins # and it is validated as edtf. The value '一九九六' at # [:date,0,:parallelValue,1] only matches [:date,0] (iso8601). encoding_path, code = find_encoding_for(path) return unless code invalid_groups[encoding_path] ||= [] invalid_groups[encoding_path] << value unless valid_value?(value, code) end |