Class: Gitlab::GrapeOpenapi::Converters::CrossFieldValidationResolver
- Inherits:
-
Object
- Object
- Gitlab::GrapeOpenapi::Converters::CrossFieldValidationResolver
- Defined in:
- lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb
Constant Summary collapse
- MUTUALLY_EXCLUSIVE =
{ classes: [ 'Grape::Validations::Validators::MutualExclusionValidator', # Grape < 3.2 'Grape::Validations::Validators::MutuallyExclusiveValidator' # Grape >= 3.2 ].freeze, notes: lambda do |groups| partners = Hash.new { |hash, key| hash[key] = [] } groups.each do |group| group.each do |name| (group - [name]).each do |other| partners[name] << other unless partners[name].include?(other) end end end partners.transform_values do |others| "Mutually exclusive with #{others.map { |name| "`#{name}`" }.join(', ')}." end end }.freeze
- CONSTRAINTS =
[MUTUALLY_EXCLUSIVE].freeze
Class Method Summary collapse
-
.append_note(description, note) ⇒ Object
Appends a note to an existing description so the two read as separate sentences.
-
.notes_for(route, attributes) ⇒ Object
For callers that need notes alone, which is every caller that has no nested scope to skip - see
#notes.
Instance Method Summary collapse
-
#initialize(route, attributes) ⇒ CrossFieldValidationResolver
constructor
attributesare the param names the caller is able to annotate: a route's query params, or a request body's top-level properties. -
#notes ⇒ Object
Per-param description notes for every cross-field constraint on the route, e.g.
-
#skipped ⇒ Object
The groups
notescould NOT annotate (a member isn't one ofattributes).
Constructor Details
#initialize(route, attributes) ⇒ CrossFieldValidationResolver
attributes are the param names the caller is able to annotate: a
route's query params, or a request body's top-level properties. Both
readers below share one walk of the route's validations, so a caller
that needs both pays for it once.
68 69 70 71 |
# File 'lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb', line 68 def initialize(route, attributes) @route = route @attributes = attributes end |
Class Method Details
.append_note(description, note) ⇒ Object
Appends a note to an existing description so the two read as separate sentences. Returns the note alone when there is no existing text.
56 57 58 59 60 61 62 |
# File 'lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb', line 56 def self.append_note(description, note) text = description.to_s.strip return note if text.empty? text += '.' unless text.end_with?('.', '!', '?') "#{text} #{note}" end |
.notes_for(route, attributes) ⇒ Object
For callers that need notes alone, which is every caller that has no
nested scope to skip - see #notes.
49 50 51 |
# File 'lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb', line 49 def self.notes_for(route, attributes) new(route, attributes).notes end |
Instance Method Details
#notes ⇒ Object
Per-param description notes for every cross-field constraint on the
route, e.g. { 'files' => 'Mutually exclusive with content.' }.
Notes from different constraints on the same param are
joined. Returns {} when there are none.
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb', line 77 def notes @notes ||= matched_entries.each_with_object({}) do |(constraint, entries), result| groups = annotatable_groups(entries) next if groups.empty? constraint[:notes].call(groups).each do |param, note| result[param] = self.class.append_note(result[param], note) end end end |
#skipped ⇒ Object
The groups notes could NOT annotate (a member isn't one of attributes).
89 90 91 92 93 |
# File 'lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb', line 89 def skipped @skipped ||= matched_entries.flat_map do |_constraint, entries| constrained_groups(entries).reject { |group| fully_known?(group) } end.uniq end |