Skip to content

Commit

Permalink
Move Swagger type decision logic to dedicated classes.
Browse files Browse the repository at this point in the history
`Apipie::Generator::Swagger::TypeExtractor` is responsible to identify
the Swagger type from a given validator or default to `string` if no
validator is given.
  • Loading branch information
PanosCodes committed Dec 27, 2022
1 parent 407f9de commit 70fbc23
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 58 deletions.
2 changes: 2 additions & 0 deletions lib/apipie-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@
require "apipie/generator/swagger/swagger"
require "apipie/generator/swagger/warning"
require "apipie/generator/swagger/warning_writer"
require "apipie/generator/swagger/type"
require "apipie/generator/swagger/type_extractor"
2 changes: 2 additions & 0 deletions lib/apipie/generator/generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Apipie::Generator
end
2 changes: 2 additions & 0 deletions lib/apipie/generator/swagger/swagger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Apipie::Generator::Swagger
end
16 changes: 16 additions & 0 deletions lib/apipie/generator/swagger/type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Apipie::Generator::Swagger::Type
attr_reader :str_format

def initialize(type, str_format = nil)
@type = type
@str_format = str_format
end

def to_s
@type
end

def ==(other)
other.to_s == self.to_s
end
end
69 changes: 69 additions & 0 deletions lib/apipie/generator/swagger/type_extractor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
class Apipie::Generator::Swagger::TypeExtractor
TYPES = {
numeric: 'number',
hash: 'object',
array: 'array',
enum: 'enum',

# see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
integer: Apipie::Generator::Swagger::Type.new('integer', 'int32'),
long: Apipie::Generator::Swagger::Type.new('integer', 'int64'),
number: Apipie::Generator::Swagger::Type.new('number'),
float: Apipie::Generator::Swagger::Type.new('number', 'float'),
double: Apipie::Generator::Swagger::Type.new('number', 'double'),
string: Apipie::Generator::Swagger::Type.new('string'),
byte: Apipie::Generator::Swagger::Type.new('string', 'byte'),
binary: Apipie::Generator::Swagger::Type.new('string', 'binary'),
boolean: Apipie::Generator::Swagger::Type.new('boolean'),
date: Apipie::Generator::Swagger::Type.new('string', 'date'),
dateTime: Apipie::Generator::Swagger::Type.new('string', 'date-time'),
password: Apipie::Generator::Swagger::Type.new('string', 'password')
}

# @param [<Apipie::Validator::BaseValidator>] validator
def initialize(validator)
@validator = validator
end

# @param [Hash<Symbol, Apipie::Generator::Swagger::Warning>] warnings
def extract_with_warnings(warnings = {})
if boolean? && warnings[:boolean].present?
Apipie::Generator::Swagger::WarningWriter.instance.warn(warnings[:boolean])
end

extract
end

private

def extract
expected_type = if string?
:string
elsif boolean?
:boolean
elsif enum?
:enum
else
@validator.expected_type.to_sym
end

TYPES[expected_type] || @validator.expected_type
end

def string?
@validator.blank?
end

def enum?
@validator.is_a?(Apipie::Validator::EnumValidator) ||
(@validator.respond_to?(:is_enum) && @validator.is_enum)
end

def boolean?
@_boolean ||= enum? && boolean_values?
end

def boolean_values?
@validator.values.to_set == Set.new([true, false])
end
end
69 changes: 11 additions & 58 deletions lib/apipie/swagger_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,68 +318,21 @@ def swagger_op_id_for_path(http_method, path)
http_method.downcase + path.gsub(/\//,'_').gsub(/:(\w+)/, '\1').gsub(/_$/,'')
end

class SwaggerTypeWithFormat
attr_reader :str_format
def initialize(type, str_format)
@type = type
@str_format = str_format
end

def to_s
@type
end

def ==(other)
other.to_s == self.to_s
end
end

def lookup
@lookup ||= {
numeric: "number",
hash: "object",
array: "array",

# see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
integer: SwaggerTypeWithFormat.new("integer", "int32"),
long: SwaggerTypeWithFormat.new("integer", "int64"),
number: SwaggerTypeWithFormat.new("number", nil), # here just for completeness
float: SwaggerTypeWithFormat.new("number", "float"),
double: SwaggerTypeWithFormat.new("number", "double"),
string: SwaggerTypeWithFormat.new("string", nil), # here just for completeness
byte: SwaggerTypeWithFormat.new("string", "byte"),
binary: SwaggerTypeWithFormat.new("string", "binary"),
boolean: SwaggerTypeWithFormat.new("boolean", nil), # here just for completeness
date: SwaggerTypeWithFormat.new("string", "date"),
dateTime: SwaggerTypeWithFormat.new("string", "date-time"),
password: SwaggerTypeWithFormat.new("string", "password"),
}
end


def swagger_param_type(param_desc)
if param_desc.nil?
raise("problem")
if param_desc.blank?
raise ArgumentError, 'param_desc is required'
end

v = param_desc.validator
if v.nil?
return "string"
end

if v.class == Apipie::Validator::EnumValidator || (v.respond_to?(:is_enum?) && v.is_enum?)
if v.values - [true, false] == [] && [true, false] - v.values == []
warn_inferring_boolean(param_desc.name)
return "boolean"
else
return "enum"
end
elsif v.class == Apipie::Validator::HashValidator
# pp v
end
method_id = ruby_name_for_method(@current_method)

warning = Apipie::Generator::Swagger::Warning.for_code(
Apipie::Generator::Swagger::Warning::INFERRING_BOOLEAN_CODE,
method_id,
{ parameter: param_desc.name }
)

return lookup[v.expected_type.to_sym] || v.expected_type
Apipie::Generator::Swagger::TypeExtractor.new(param_desc.validator).
extract_with_warnings({ boolean: warning })
end


Expand Down Expand Up @@ -515,7 +468,7 @@ def save_field(entry, openapi_key, v, apipie_key=openapi_key, translate=false)

swg_param_type = swagger_param_type(param_desc)
swagger_def[:type] = swg_param_type.to_s
if (swg_param_type.is_a? SwaggerTypeWithFormat) && !swg_param_type.str_format.nil?
if (swg_param_type.is_a? Apipie::Generator::Swagger::Type) && !swg_param_type.str_format.nil?
swagger_def[:format] = swg_param_type.str_format
end

Expand Down
61 changes: 61 additions & 0 deletions spec/lib/generator/swagger/type_extractor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require 'spec_helper'

describe Apipie::Generator::Swagger::TypeExtractor do
let(:validator) {}
let(:extractor) { described_class.new(validator) }

describe '#extarct_with_warnings' do
let(:warnings) { {} }

before { Apipie.configuration.swagger_suppress_warnings = false }

subject { extractor.extract_with_warnings(warnings) }

it { is_expected.to eq(Apipie::Generator::Swagger::TypeExtractor::TYPES[:string]) }

context "when enum validator is used" do
let(:enum_values) { ["Name"] }

context "of type Apipie::Validator::EnumValidator" do
let(:validator) { Apipie::Validator::EnumValidator.new(nil, enum_values) }

it { is_expected.to eq("enum") }
end

context "that responds to is_enum?" do
let(:validator) do
Apipie::ResponseDescriptionAdapter::PropDesc::Validator.new('some-type', enum_values)
end

it 'returns an enum type' do
expect(subject).to eq(Apipie::Generator::Swagger::TypeExtractor::TYPES[:enum])
end

context 'and has `true`, `false` as values' do
let(:param_description_name) { :visible }
let(:enum_values) { [true, false] }

it 'returns a boolean type' do
expect(subject).to eq(Apipie::Generator::Swagger::TypeExtractor::TYPES[:boolean])
end

context 'and a boolean warning is passed' do
let(:boolean_warning) do
Apipie::Generator::Swagger::Warning.for_code(
Apipie::Generator::Swagger::Warning::INFERRING_BOOLEAN_CODE,
'SampleController#action',
{ parameter: 'some-param' }
)
end

let(:warnings) { { boolean: boolean_warning } }

it 'outputs the warning' do
expect { subject }.to output(boolean_warning.warning_message).to_stderr
end
end
end
end
end
end
end

0 comments on commit 70fbc23

Please sign in to comment.