Class: Solargraph::ComplexType

Inherits:
Object
  • Object
show all
Includes:
Equality
Defined in:
lib/solargraph/complex_type.rb,
lib/solargraph/complex_type/unique_type.rb,
lib/solargraph/complex_type/type_methods.rb

Overview

A container for type data based on YARD type tags.

Defined Under Namespace

Modules: TypeMethods Classes: UniqueType

Constant Summary collapse

GENERIC_TAG_NAME =
'generic'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Equality

#==, #eql?, #freeze, #hash

Constructor Details

#initialize(types = [UniqueType::UNDEFINED]) ⇒ ComplexType

Returns a new instance of ComplexType.

Parameters:



16
17
18
19
20
# File 'lib/solargraph/complex_type.rb', line 16

def initialize types = [UniqueType::UNDEFINED]
  # @todo @items here should not need an annotation
  # @type [Array<UniqueType>]
  @items = types.flat_map(&:items).uniq(&:to_s)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object?

Parameters:

  • name (Symbol)

Returns:

  • (Object, nil)


134
135
136
137
138
# File 'lib/solargraph/complex_type.rb', line 134

def method_missing name, *args, &block
  return if @items.first.nil?
  return @items.first.send(name, *args, &block) if respond_to_missing?(name)
  super
end

Instance Attribute Details

#itemsObject (readonly)

Returns the value of attribute items.



233
234
235
# File 'lib/solargraph/complex_type.rb', line 233

def items
  @items
end

Class Method Details

.parse(*strings, partial: false) ⇒ ComplexType

TODO:

To be able to select the right signature above, Chain::Call needs to know the decl type (:arg, :optarg, :kwarg, etc) of the arguments given, instead of just having an array of Chains as the arguments.

Note:

The ‘partial` parameter is used to indicate that the method is receiving a string that will be used inside another ComplexType. It returns arrays of ComplexTypes instead of a single cohesive one. Consumers should not need to use this parameter; it should only be used internally.

Parse type strings into a ComplexType.

# @overload parse(*strings, partial: false) # @todo Need ability to use a literal true as a type below # @param partial [Boolean] True if the string is part of a another type # @return [Array<UniqueType>] @sg-ignore

Examples:

ComplexType.parse 'String', 'Foo', 'nil' #=> [String, Foo, nil]

Parameters:

  • strings (Array<String>)

    The type definitions to parse

Returns:



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/solargraph/complex_type.rb', line 278

def parse *strings, partial: false
  # @type [Hash{Array<String> => ComplexType}]
  @cache ||= {}
  unless partial
    cached = @cache[strings]
    return cached unless cached.nil?
  end
  types = []
  key_types = nil
  strings.each do |type_string|
    point_stack = 0
    curly_stack = 0
    paren_stack = 0
    base = String.new
    subtype_string = String.new
    type_string&.each_char do |char|
      if char == '='
        #raise ComplexTypeError, "Invalid = in type #{type_string}" unless curly_stack > 0
      elsif char == '<'
        point_stack += 1
      elsif char == '>'
        if subtype_string.end_with?('=') && curly_stack > 0
          subtype_string += char
        elsif base.end_with?('=')
          raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
          # types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
          types.push UniqueType.parse(base[0..-2].strip, subtype_string)
          # @todo this should either expand key_type's type
          #   automatically or complain about not being
          #   compatible with key_type's type in type checking
          key_types = types
          types = []
          base.clear
          subtype_string.clear
          next
        else
          raise ComplexTypeError, "Invalid close in type #{type_string}" if point_stack == 0
          point_stack -= 1
          subtype_string += char
        end
        next
      elsif char == '{'
        curly_stack += 1
      elsif char == '}'
        curly_stack -= 1
        subtype_string += char
        raise ComplexTypeError, "Invalid close in type #{type_string}" if curly_stack < 0
        next
      elsif char == '('
        paren_stack += 1
      elsif char == ')'
        paren_stack -= 1
        subtype_string += char
        raise ComplexTypeError, "Invalid close in type #{type_string}" if paren_stack < 0
        next
      elsif char == ',' && point_stack == 0 && curly_stack == 0 && paren_stack == 0
        # types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
        types.push UniqueType.parse(base.strip, subtype_string.strip)
        base.clear
        subtype_string.clear
        next
      end
      if point_stack == 0 && curly_stack == 0 && paren_stack == 0
        base.concat char
      else
        subtype_string.concat char
      end
    end
    raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 || curly_stack != 0 || paren_stack != 0
    # types.push ComplexType.new([UniqueType.new(base, subtype_string)])
    types.push UniqueType.parse(base.strip, subtype_string.strip)
  end
  unless key_types.nil?
    raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
    return key_types if types.empty?
    return [key_types, types]
  end
  result = partial ? types : ComplexType.new(types)
  @cache[strings] = result unless partial
  result
end

.try_parse(*strings) ⇒ ComplexType

Parameters:

  • strings (Array<String>)

Returns:



362
363
364
365
366
367
# File 'lib/solargraph/complex_type.rb', line 362

def try_parse *strings
  parse *strings
rescue ComplexTypeError => e
  Solargraph.logger.info "Error parsing complex type `#{strings.join(', ')}`: #{e.message}"
  ComplexType::UNDEFINED
end

Instance Method Details

#[](index) ⇒ UniqueType

Parameters:

  • index (Integer)

Returns:



112
113
114
# File 'lib/solargraph/complex_type.rb', line 112

def [](index)
  @items[index]
end

#all? {|| ... } ⇒ Boolean

Yield Parameters:

Returns:

  • (Boolean)


159
160
161
# File 'lib/solargraph/complex_type.rb', line 159

def all? &block
  @items.all? &block
end

#all_paramsArray<ComplexType>

Returns:



207
208
209
# File 'lib/solargraph/complex_type.rb', line 207

def all_params
  @items.first.all_params || []
end

#all_rooted?Boolean

every type and subtype in this union have been resolved to be fully qualified

Returns:

  • (Boolean)


223
224
225
# File 'lib/solargraph/complex_type.rb', line 223

def all_rooted?
  all?(&:all_rooted?)
end

#any? {|| ... } ⇒ Boolean

Yield Parameters:

Yield Returns:

  • (Boolean)

Returns:

  • (Boolean)


166
167
168
# File 'lib/solargraph/complex_type.rb', line 166

def any? &block
  @items.compact.any? &block
end

#descObject



150
151
152
# File 'lib/solargraph/complex_type.rb', line 150

def desc
  rooted_tags
end

#each {|| ... } ⇒ Enumerable<UniqueType>

Yield Parameters:

Returns:



80
81
82
# File 'lib/solargraph/complex_type.rb', line 80

def each &block
  @items.each &block
end

#each_unique_typeEnumerator<UniqueType>

This method returns an undefined value.

Returns:

Yield Parameters:



88
89
90
91
92
93
94
# File 'lib/solargraph/complex_type.rb', line 88

def each_unique_type &block
  return enum_for(__method__) unless block_given?

  @items.each do |item|
    item.each_unique_type &block
  end
end

#firstUniqueType

Returns:



51
52
53
# File 'lib/solargraph/complex_type.rb', line 51

def first
  @items.first
end

#force_rootedself

Returns:

  • (self)


188
189
190
191
192
# File 'lib/solargraph/complex_type.rb', line 188

def force_rooted
  transform do |t|
    t.recreate(make_rooted: true)
  end
end

#generic?Boolean

Returns:

  • (Boolean)


174
175
176
# File 'lib/solargraph/complex_type.rb', line 174

def generic?
  any?(&:generic?)
end

#lengthInteger

Returns:

  • (Integer)


97
98
99
# File 'lib/solargraph/complex_type.rb', line 97

def length
  @items.length
end

#map {|| ... } ⇒ Array

Yield Parameters:

Returns:

  • (Array)


74
75
76
# File 'lib/solargraph/complex_type.rb', line 74

def map &block
  @items.map &block
end

#namespaceString

Returns:

  • (String)


122
123
124
125
# File 'lib/solargraph/complex_type.rb', line 122

def namespace
  # cache this attr for high frequency call
  @namespace ||= method_missing(:namespace).to_s
end

#namespacesArray<String>

Returns:

  • (Array<String>)


128
129
130
# File 'lib/solargraph/complex_type.rb', line 128

def namespaces
  @items.map(&:namespace)
end

#nullable?Boolean

Returns:

  • (Boolean)


202
203
204
# File 'lib/solargraph/complex_type.rb', line 202

def nullable?
  @items.any?(&:nil_type?)
end

#qualify(api_map, context = '') ⇒ ComplexType

Parameters:

  • api_map (ApiMap)
  • context (String) (defaults to: '')

Returns:



30
31
32
33
34
35
36
37
38
# File 'lib/solargraph/complex_type.rb', line 30

def qualify api_map, context = ''
  red = reduce_object
  types = red.items.map do |t|
    next t if ['nil', 'void', 'undefined'].include?(t.name)
    next t if ['::Boolean'].include?(t.rooted_name)
    t.qualify api_map, context
  end
  ComplexType.new(types).reduce_object
end

#reduce_class_typeComplexType

Returns:



212
213
214
215
216
217
218
219
# File 'lib/solargraph/complex_type.rb', line 212

def reduce_class_type
  new_items = items.flat_map do |type|
    next type unless ['Module', 'Class'].include?(type.name)

    type.all_params
  end
  ComplexType.new(new_items)
end

#resolve_generics(definitions, context_type) ⇒ ComplexType

Parameters:

Returns:



197
198
199
200
# File 'lib/solargraph/complex_type.rb', line 197

def resolve_generics definitions, context_type
  result = @items.map { |i| i.resolve_generics(definitions, context_type) }
  ComplexType.new(result)
end

#resolve_generics_from_context(generics_to_resolve, context_type, resolved_generic_values: {}) ⇒ self

Parameters:

  • generics_to_resolve (Enumerable<String>)

    ]

  • context_type (UniqueType, nil)
  • resolved_generic_values (Hash{String => ComplexType}) (defaults to: {})

    Added to as types are encountered or resolved

Returns:

  • (self)


44
45
46
47
48
# File 'lib/solargraph/complex_type.rb', line 44

def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
  return self unless generic?

  ComplexType.new(@items.map { |i| i.resolve_generics_from_context(generics_to_resolve, context_type, resolved_generic_values: resolved_generic_values) })
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Parameters:

  • name (Symbol)
  • include_private (Boolean) (defaults to: false)

Returns:

  • (Boolean)


142
143
144
# File 'lib/solargraph/complex_type.rb', line 142

def respond_to_missing?(name, include_private = false)
  TypeMethods.public_instance_methods.include?(name) || super
end

#rooted?Boolean

every top-level type has resolved to be fully qualified; see #all_rooted? to check their subtypes as well

Returns:

  • (Boolean)


229
230
231
# File 'lib/solargraph/complex_type.rb', line 229

def rooted?
  all?(&:rooted?)
end

#rooted_tagsObject



154
155
156
# File 'lib/solargraph/complex_type.rb', line 154

def rooted_tags
  map(&:rooted_tag).join(', ')
end

#select(&block) ⇒ Array<UniqueType>

Returns:



117
118
119
# File 'lib/solargraph/complex_type.rb', line 117

def select &block
  @items.select &block
end

#self_to_type(dst) ⇒ ComplexType

Parameters:

Returns:



64
65
66
67
68
69
70
# File 'lib/solargraph/complex_type.rb', line 64

def self_to_type dst
  object_type_dst = dst.reduce_class_type
  transform do |t|
    next t if t.name != 'self'
    object_type_dst
  end
end

#selfy?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/solargraph/complex_type.rb', line 170

def selfy?
  @items.any?(&:selfy?)
end

#tagsObject



106
107
108
# File 'lib/solargraph/complex_type.rb', line 106

def tags
  @items.map(&:tag).join(', ')
end

#to_aArray<UniqueType>

Returns:



102
103
104
# File 'lib/solargraph/complex_type.rb', line 102

def to_a
  @items
end

#to_rbsString

Returns:

  • (String)


56
57
58
59
60
# File 'lib/solargraph/complex_type.rb', line 56

def to_rbs
  ((@items.length > 1 ? '(' : '') +
   @items.map(&:to_rbs).join(' | ') +
   (@items.length > 1 ? ')' : ''))
end

#to_sObject



146
147
148
# File 'lib/solargraph/complex_type.rb', line 146

def to_s
  map(&:tag).join(', ')
end

#transform(new_name = nil) {|t| ... } ⇒ ComplexType

Parameters:

  • new_name (String, nil) (defaults to: nil)

Yield Parameters:

Yield Returns:

Returns:



182
183
184
185
# File 'lib/solargraph/complex_type.rb', line 182

def transform(new_name = nil, &transform_type)
  raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
  ComplexType.new(map { |ut| ut.transform(new_name, &transform_type) })
end