zhandao/zero-rails_openapi

View on GitHub
lib/open_api.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'colorize'

require 'open_api/version'
require 'open_api/support/tip'
require 'open_api/config'
require 'open_api/router'
require 'open_api/dsl'

module OpenApi
  module_function
  cattr_accessor(:routes_index) { { } }
  cattr_accessor(:docs) { { } }

  def write_docs(if: true, read_on_controller: true)
    (docs = generate_docs(read_on_controller)) and Tip.loaded
    return unless binding.local_variable_get :if

    FileUtils.mkdir_p Config.file_output_path
    docs.each do |name, doc|
      File.write "#{Config.file_output_path}/#{name}.json", JSON.pretty_generate(doc)
      Tip.generated(name.to_s.rjust(docs.keys.map(&:size).max))
    end
  end

  def generate_docs(read_on_controller)
    return Tip.no_config if Config.docs.keys.blank?
    traverse_controllers if read_on_controller
    Dir[*Array(Config.doc_location)].each { |file| require file }
    Config.docs.keys.map { |name| [ name, generate_doc(name) ] }.to_h
  end

  def generate_doc(doc_name)
    settings, doc = init_hash(doc_name)
    [*(bdc = settings[:base_doc_classes]), *bdc.flat_map(&:descendants)].each do |kls|
      next if kls.oas[:doc].blank?
      doc[:paths].merge!(kls.oas[:apis])
      doc[:tags] << kls.oas[:doc][:tag]
      doc[:components].deep_merge!(kls.oas[:doc][:components] || { })
      OpenApi.routes_index[kls.oas[:route_base]] = doc_name
    end

    doc[:components].delete_if { |_, v| v.blank? }
    doc[:tags]  = doc[:tags].sort { |a, b| a[:name] <=> b[:name] }
    doc[:paths] = doc[:paths].sort.to_h
    OpenApi.docs[doc_name] = doc#.delete_if { |_, v| v.blank? }
  end

  def init_hash(doc_name)
    settings = Config.docs[doc_name]
    doc = { openapi: '3.0.0', **settings.slice(:info, :servers) }.merge!(
        security: settings[:global_security] || [], tags: [ ], paths: { },
        components: {
            securitySchemes: settings[:securitySchemes] || { },
            schemas: { }, parameters: { }, requestBodies: { }
        }
    )
    [ settings, doc ]
  end

  def traverse_controllers
    Dir['./app/controllers/**/*_controller.rb'].each do |file|
      file.sub('./app/controllers/', '').sub('.rb', '').camelize.constantize
    end
  end
end