Class: Solargraph::ComplexType

Inherits:
Object
  • Object
show all
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

Constructor Details

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

Returns a new instance of ComplexType.

Parameters:



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

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)


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

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.



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

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:



277
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
# File 'lib/solargraph/complex_type.rb', line 277

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:



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

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

#==(other) ⇒ Object



26
27
28
# File 'lib/solargraph/complex_type.rb', line 26

def ==(other)
  self.eql?(other)
end

#[](index) ⇒ UniqueType

Parameters:

  • index (Integer)

Returns:



119
120
121
# File 'lib/solargraph/complex_type.rb', line 119

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

#all?(&block) ⇒ Boolean

Returns:

  • (Boolean)


161
162
163
# File 'lib/solargraph/complex_type.rb', line 161

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

#all_paramsArray<ComplexType>

Returns:



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

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)


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

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

#any?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

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

Yield Parameters:

Returns:



87
88
89
# File 'lib/solargraph/complex_type.rb', line 87

def each &block
  @items.each &block
end

#each_unique_typeEnumerator<UniqueType>

This method returns an undefined value.

Returns:

Yield Parameters:



95
96
97
98
99
100
101
# File 'lib/solargraph/complex_type.rb', line 95

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

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

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


21
22
23
24
# File 'lib/solargraph/complex_type.rb', line 21

def eql?(other)
  self.class == other.class &&
    @items == other.items
end

#firstUniqueType

Returns:



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

def first
  @items.first
end

#force_rootedself

Returns:

  • (self)


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

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

#generic?Boolean

Returns:

  • (Boolean)


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

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

#hashObject



30
31
32
# File 'lib/solargraph/complex_type.rb', line 30

def hash
  [self.class, @items].hash
end

#lengthInteger

Returns:

  • (Integer)


104
105
106
# File 'lib/solargraph/complex_type.rb', line 104

def length
  @items.length
end

#map {|| ... } ⇒ Array

Yield Parameters:

Returns:

  • (Array)


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

def map &block
  @items.map &block
end

#namespaceString

Returns:

  • (String)


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

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

#namespacesArray<String>

Returns:

  • (Array<String>)


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

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

#nullable?Boolean

Returns:

  • (Boolean)


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

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

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

Parameters:

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

Returns:



37
38
39
40
41
42
43
44
45
# File 'lib/solargraph/complex_type.rb', line 37

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:



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

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:



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

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)


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

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)


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

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)


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

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

#rooted_tagsObject



157
158
159
# File 'lib/solargraph/complex_type.rb', line 157

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

#select(&block) ⇒ Array<UniqueType>

Returns:



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

def select &block
  @items.select &block
end

#self_to_type(dst) ⇒ ComplexType

Parameters:

Returns:



71
72
73
74
75
76
77
# File 'lib/solargraph/complex_type.rb', line 71

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)


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

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

#tagsObject



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

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

#to_aArray<UniqueType>

Returns:



109
110
111
# File 'lib/solargraph/complex_type.rb', line 109

def to_a
  @items
end

#to_rbsString

Returns:

  • (String)


63
64
65
66
67
# File 'lib/solargraph/complex_type.rb', line 63

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

#to_sObject



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

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:



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

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