class Argtrace::OutputModule

helper to convert TypeLib into RBS. OutputMoudle acts like Module tree node.

Attributes

actual_module[RW]
children[RW]
name[RW]
signatures[RW]

Public Class Methods

new() click to toggle source
# File lib/argtrace/typelib.rb, line 157
def initialize
  @children = {}
  @signatures = []
end

Public Instance Methods

add_signature(signature) click to toggle source
# File lib/argtrace/typelib.rb, line 162
def add_signature(signature)
  # this is root node, so use Kernel as const resolve source.
  @actual_module = Kernel

  constname = class_const_name(signature.defined_class)
  add_signature_inner(constname, signature)
end
add_signature_inner(name_consts, signature) click to toggle source
# File lib/argtrace/typelib.rb, line 176
def add_signature_inner(name_consts, signature)
  if name_consts.empty?
    @signatures << signature
  else
    unless @children.key?(name_consts.first)
      mod = OutputModule.new
      mod.name = name_consts.first
      mod.actual_module = @actual_module.const_get(name_consts.first)
      @children[name_consts.first] = mod
    end
    current_resolving_name = name_consts.shift
    @children[current_resolving_name].add_signature_inner(name_consts, signature)
  end
end
blocktype_to_rbs(blockparam) click to toggle source
# File lib/argtrace/typelib.rb, line 231
def blocktype_to_rbs(blockparam)
  unless blockparam
    return ""
  end
  params = blockparam.type.params
    .map{|p| type_union_to_rbs(p.type)}
    .join(", ")
  return " { (#{params}) -> untyped }"
end
class_const_name(klass) click to toggle source

split class name into consts (e.g. Argtrace::TypeLib to [“Argtrace”, “TypeLib”]) bad name class is already sanitized, just split.

# File lib/argtrace/typelib.rb, line 172
def class_const_name(klass)
  klass.to_s.split("::")
end
param_to_rbs(param) click to toggle source
# File lib/argtrace/typelib.rb, line 241
def param_to_rbs(param)
  case param.mode
  when :req
    return "#{type_union_to_rbs(param.type)} #{param.name}"
  when :opt
    return "?#{type_union_to_rbs(param.type)} #{param.name}"
  when :keyreq
    return "#{param.name}: #{type_union_to_rbs(param.type)}"
  when :key
    return "?#{param.name}: #{type_union_to_rbs(param.type)}"
  when :block
    return nil
  end
end
sig_to_rbs(indent_level, signature) click to toggle source
# File lib/argtrace/typelib.rb, line 218
def sig_to_rbs(indent_level, signature)
  indent = "  " * indent_level
  sig_name = signature.is_singleton_method ? "self.#{signature.method_id}" : signature.method_id
  params = signature.params
    .filter{|p| p.mode != :block}
    .map{|p| param_to_rbs(p)}
    .compact
    .join(", ")
  rettype = type_union_to_rbs(signature.return_type)
  blocktype = blocktype_to_rbs(signature.params.find{|p| p.mode == :block})
  return "#{indent}def #{sig_name} : (#{params})#{blocktype} -> #{rettype}"
end
to_rbs() click to toggle source
# File lib/argtrace/typelib.rb, line 191
def to_rbs
  # this is root node
  lines = []
  @children.keys.sort.each do |child_name|
    lines << @children[child_name].to_rbs_inner(0)
    lines << ""
  end
  return lines.join("\n")
end
to_rbs_inner(indent_level) click to toggle source
# File lib/argtrace/typelib.rb, line 201
def to_rbs_inner(indent_level)
  indent = "  " * indent_level
  classmod_def = @actual_module.class == Class ? "class" : "module"

  lines = []
  lines << "#{indent}#{classmod_def} #{name}"
  @children.keys.sort.each do |child_name|
    lines << @children[child_name].to_rbs_inner(indent_level + 1)
    lines << ""
  end
  @signatures.each do |sig|
    lines << sig_to_rbs(indent_level + 1, sig)
  end
  lines << "#{indent}end"
  return lines.join("\n")
end
type_to_rbs(type) click to toggle source
# File lib/argtrace/typelib.rb, line 280
def type_to_rbs(type)
  if type.data.is_a?(Symbol)
    return type.data.inspect
  elsif true == type.data || false == type.data || BooleanClass == type.data
    return "bool"
  elsif nil == type.data || NilClass == type.data
    return "nil"
  elsif Array == type.data
    if type.subdata
      case type.subdata
      when true, false, BooleanClass
        elementtype = "bool"
      else
        elementtype = type.subdata.to_s
      end
      return "Array[#{elementtype}]"
    else
      return "Array"
    end
  else
    return type.data.to_s
  end
end
type_union_to_rbs(typeunion) click to toggle source
# File lib/argtrace/typelib.rb, line 256
def type_union_to_rbs(typeunion)
  if typeunion.union.size == 0
    return "untyped"
  end
  # TODO: ugly
  if typeunion.union.size == 1 and NilClass == typeunion.union.first.data
    # TODO: I can't distinguish nil and untyped.
    return "untyped"
  end
  if typeunion.union.count{|x| x.data.is_a?(Symbol)} >= 16
    # too much symbols, this should not be enum.
    typeunion.union.delete_if{|x| x.data.is_a?(Symbol)}
    typeunion.add(Type.new_with_type(Symbol))
  end
  if typeunion.union.size == 2 and typeunion.union.any?{|x| NilClass == x.data}
    # type is nil and sometype, so represent it as "sometype?"
    sometype = typeunion.union.find{|x| NilClass != x.data}
    return "#{type_to_rbs(sometype)}?"
  end

  ret = typeunion.union.map{|type| type_to_rbs(type)}.join("|")
  return ret
end