module OasRails::Extractors::RenderResponseExtractor

def build_array_model_schema_and_examples(maybe_a_model, klass, schema)

Returns:
  • (Array) - An array where the first element is the schema and the second is the examples.

Parameters:
  • schema (Hash) -- The schema for the model.
  • klass (Class) -- The class associated with the model.
  • maybe_a_model (String) -- The model name or variable.
def build_array_model_schema_and_examples(maybe_a_model, klass, schema)
  examples = { maybe_a_model => { value: Spec::MediaType.search_for_examples_in_tests(klass, context: :outgoing).values.map { |p| p.dig(:value, maybe_a_model.singularize.to_sym) } } }
  [{ type: "array", items: schema }, examples]
end

def build_schema_and_examples(content)

Returns:
  • (Array) - An array where the first element is the schema and the second is the examples.

Parameters:
  • content (String) -- The content extracted from the render call.
def build_schema_and_examples(content)
  if content.start_with?('{')
    [Utils.hash_to_json_schema(parse_hash_structure(content)), {}]
  else
    process_non_hash_content(content)
  end
rescue StandardError => e
  Rails.logger.debug("Error building schema: #{e.message}")
  [{}]
end

def build_singular_model_schema_and_examples(_maybe_a_model, errors, klass, schema)

Returns:
  • (Array) - An array where the first element is the schema and the second is the examples.

Parameters:
  • schema (Hash) -- The schema for the model.
  • klass (Class) -- The class associated with the model.
  • errors (String, nil) -- Errors related to the model.
  • maybe_a_model (String) -- The model name or variable.
def build_singular_model_schema_and_examples(_maybe_a_model, errors, klass, schema)
  if errors.nil?
    [schema, Spec::MediaType.search_for_examples_in_tests(klass, context: :outgoing)]
  else
    # TODO: this is not building the real schema.
    [
      {
        type: "object",
        properties: {
          success: { type: "boolean" },
          errors: {
            type: "object",
            additionalProperties: {
              type: "array",
              items: { type: "string" }
            }
          }
        }
      },
      {}
    ]
  end
end

def extract_render_calls(source)

Returns:
  • (Array>) - An array of arrays, each containing render content and status.

Parameters:
  • source (String) -- The source string containing render calls.
def extract_render_calls(source)
  source.scan(/render json: ((?:\{.*?\}|\S+))(?:, status: :(\w+))?(?:,.*?)?$/m)
end

def extract_responses_from_source(specification, source:)

Returns:
  • (Array) - An array of Response objects extracted from the source.

Parameters:
  • source (String) -- The source string containing render calls.
def extract_responses_from_source(specification, source:)
  render_calls = extract_render_calls(source)
  return [Builders::ResponseBuilder.new(specification).with_description("No content").with_code(204).build] if render_calls.empty?
  render_calls.map { |render_content, status| process_render_content(specification, render_content.strip, status) }
end

def parse_hash_structure(hash_literal)

Returns:
  • (Hash) - A hash representing the structure of the input.

Parameters:
  • hash_literal (String) -- The hash literal string.
def parse_hash_structure(hash_literal)
  structure = {}
  hash_literal.scan(/(\w+):\s*(\S+)/) do |key, value|
    structure[key.to_sym] = case value
                            when 'true', 'false'
                              'Boolean'
                            when /^\d+$/
                              'Number'
                            else
                              'Object'
                            end
  end
  structure
end

def process_non_hash_content(content)

Returns:
  • (Array) - An array where the first element is the schema and the second is the examples.

Parameters:
  • content (String) -- The content extracted from the render call.
def process_non_hash_content(content)
  maybe_a_model, errors = content.gsub('@', "").split(".")
  klass = maybe_a_model.singularize.camelize(:upper).constantize
  if klass.ancestors.include?(ActiveRecord::Base)
    schema = Builders::EsquemaBuilder.build_outgoing_schema(klass:)
    if test_singularity(maybe_a_model)
      build_singular_model_schema_and_examples(maybe_a_model, errors, klass, schema)
    else
      build_array_model_schema_and_examples(maybe_a_model, klass, schema)
    end
  else
    [{}]
  end
end

def process_render_content(specification, content, status)

Returns:
  • (Response) - A Response object based on the processed content and status.

Parameters:
  • status (String) -- The status code associated with the render call.
  • content (String) -- The content extracted from the render call.
def process_render_content(specification, content, status)
  schema, examples = build_schema_and_examples(content)
  status_int = Utils.status_to_integer(status)
  content = Builders::ContentBuilder.new(specification, :outgoing).with_schema(schema).with_examples(examples).build
  Builders::ResponseBuilder.new(specification).with_code(status_int).with_description(Utils.get_definition(status_int)).with_content(content).build
end

def test_singularity(str)

Returns:
  • (Boolean) - True if the string is a singular model, false otherwise.

Parameters:
  • str (String) -- The string to test.
def test_singularity(str)
  str.pluralize != str && str.singularize == str
end