Module: GrapeOAS::ApiModelBuilders::Concerns::TypeResolver

Included in:
Request, RequestParamsSupport::ParamSchemaBuilder, Introspectors::DryIntrospectorSupport::TypeSchemaBuilder, Introspectors::EntityIntrospector
Defined in:
lib/grape_oas/api_model_builders/concerns/type_resolver.rb

Overview

Centralizes Ruby type to OpenAPI schema type resolution. Used by request builders and introspectors to avoid duplicated type switching logic.

Constant Summary collapse

TYPED_ARRAY_PATTERN =
Constants::TypePatterns::TYPED_ARRAY
MULTI_TYPE_PATTERN =
Constants::TypePatterns::MULTI_TYPE

Instance Method Summary collapse

Instance Method Details

#build_array_items_schema(member) ⇒ ApiModel::Schema

Builds schema for array items, handling nested arrays recursively.

Parameters:

  • member (Object, nil)

    The member type

Returns:



118
119
120
121
122
123
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 118

def build_array_items_schema(member)
  return default_string_schema unless member

  member_primitive, member_member = derive_primitive_and_member(member)
  build_schema_for_primitive(member_primitive, member: member_member)
end

#build_schema_for_primitive(primitive, member: nil) ⇒ ApiModel::Schema

Builds a basic Schema object for the given Ruby primitive type. Handles special cases like Array and Hash. Note: Uses == instead of case/when because Ruby’s === doesn’t work for class equality (Array === Array returns false since Array is not an instance of Array)

Parameters:

  • primitive (Class, nil)

    The Ruby primitive class

  • member (Object, nil) (defaults to: nil)

    For arrays, the member type

Returns:



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 100

def build_schema_for_primitive(primitive, member: nil)
  if primitive == Array
    items_schema = build_array_items_schema(member)
    ApiModel::Schema.new(type: Constants::SchemaTypes::ARRAY, items: items_schema)
  elsif primitive == Hash
    ApiModel::Schema.new(type: Constants::SchemaTypes::OBJECT)
  else
    ApiModel::Schema.new(
      type: resolve_schema_type(primitive),
      format: Constants.format_for_type(primitive),
    )
  end
end

#derive_primitive_and_member(type) ⇒ Array<Class, Object>

Derives primitive type and nested member from a type. For Dry::Types, extracts the primitive and member type. For plain Ruby classes, returns the class with nil member.

Parameters:

  • type (Object)

    The type to analyze

Returns:

  • (Array<Class, Object>)
    primitive, member

    tuple



131
132
133
134
135
136
137
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 131

def derive_primitive_and_member(type)
  return [type, nil] unless type.respond_to?(:primitive)

  primitive = type.primitive
  member = type.respond_to?(:member) ? type.member : nil
  [primitive, member]
end

#extract_multi_types(type) ⇒ Array<String>?

Extracts individual types from Grape’s multi-type notation “[String, Integer]” Returns nil if not a multi-type notation.

Parameters:

  • type (String)

    The type string to parse

Returns:

  • (Array<String>, nil)

    Array of type names or nil



83
84
85
86
87
88
89
90
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 83

def extract_multi_types(type)
  return nil unless type.is_a?(String)

  match = type.match(MULTI_TYPE_PATTERN)
  return nil unless match

  match[1].split(/,\s*/)
end

#extract_typed_array_member(type) ⇒ String?

Extracts the member type from Grape’s “[Type]” notation. Returns nil if not a typed array.

Parameters:

  • type (String)

    The type string to parse

Returns:

  • (String, nil)

    The inner type or nil



61
62
63
64
65
66
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 61

def extract_typed_array_member(type)
  return nil unless type.is_a?(String)

  match = type.match(TYPED_ARRAY_PATTERN)
  match ? match[:inner] : nil
end

#grape_boolean_type?(type) ⇒ Boolean

Checks if type is Grape’s Boolean class (handles dynamic loading)

Returns:

  • (Boolean)


50
51
52
53
54
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 50

def grape_boolean_type?(type)
  return false unless defined?(Grape::API::Boolean)

  type == Grape::API::Boolean || type.to_s == "Grape::API::Boolean"
end

#multi_type?(type) ⇒ Boolean

Checks if type is a multi-type notation like “[String, Integer]”

Parameters:

  • type (String)

    The type string to check

Returns:

  • (Boolean)

    true if multi-type notation



72
73
74
75
76
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 72

def multi_type?(type)
  return false unless type.is_a?(String)

  type.match?(MULTI_TYPE_PATTERN)
end

#resolve_schema_type(type) ⇒ String

Resolves a Ruby class or type name to its OpenAPI schema type string. Handles both Ruby classes (Integer, Float) and string type names (“integer”, “float”). Also handles Grape’s “[Type]” notation for typed arrays. Falls back to “string” for unknown types.

Parameters:

  • type (Class, String, Symbol, nil)

    The type to resolve

Returns:

  • (String)

    The OpenAPI schema type



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/grape_oas/api_model_builders/concerns/type_resolver.rb', line 25

def resolve_schema_type(type)
  return Constants::SchemaTypes::STRING if type.nil?

  # Handle Ruby classes directly
  if type.is_a?(Class)
    # Check static mapping first
    mapped = Constants::RUBY_TYPE_MAPPING[type]
    return mapped if mapped

    # Handle Grape::API::Boolean dynamically (may not be loaded at constant definition time)
    return Constants::SchemaTypes::BOOLEAN if grape_boolean_type?(type)

    return Constants::SchemaTypes::STRING
  end

  type_str = type.to_s

  # Handle Grape's typed array notation like "[String]"
  return Constants::SchemaTypes::ARRAY if type_str.match?(TYPED_ARRAY_PATTERN)

  # Handle string/symbol type names
  Constants.primitive_type(type_str) || Constants::SchemaTypes::STRING
end