Module: Minitwin::ClassMethods::Rbs

Included in:
Minitwin::ClassMethods
Defined in:
lib/minitwin/class_methods/rbs.rb,
sig/generated/minitwin/class_methods/rbs.rbs

Instance Method Summary collapse

Instance Method Details

#dry_type_to_rbs(dry_type) ⇒ Object

Parameters:

  • dry_type (Object)

Returns:

  • (Object)


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/minitwin/class_methods/rbs.rb', line 85

def dry_type_to_rbs(dry_type)
  return "untyped" unless dry_type

  if dry_type.respond_to?(:primitive) && dry_type.primitive
    prim = dry_type.primitive
    if [TrueClass, FalseClass].include?(prim)
      "bool"
    elsif prim.is_a?(Class) && prim.name
      "::#{prim.name}"
    else
      "untyped"
    end
  else
    s =
      begin
        dry_type.to_s
      rescue StandardError
        ""
      end
    i =
      begin
        dry_type.inspect
      rescue StandardError
        ""
      end
    blob = [s, i, dry_type.class.name].join(" ")
    return "bool" if blob.include?("Bool")
    return "::Integer" if blob.include?("Integer")
    return "::String" if blob.include?("String")
    return "::Float" if blob.include?("Float")

    begin
      v1 = dry_type.call(true)
      v2 = dry_type.call(false)
      return "bool" if [true, false].include?(v1) && [true, false].include?(v2)
    rescue StandardError
      # Expected: Type coercion may fail for non-boolean types.
      # Continue to fallback 'untyped'.
    end
    "untyped"
  end
end

#rbs_class_name(klass) ⇒ Object

Parameters:

  • klass (Object)

Returns:

  • (Object)


79
80
81
82
83
# File 'lib/minitwin/class_methods/rbs.rb', line 79

def rbs_class_name(klass)
  return "untyped" unless klass&.name

  "::#{klass.name}"
end

#rbs_elem_type_for(meta) ⇒ Object

Parameters:

  • meta (Object)

Returns:

  • (Object)


71
72
73
74
75
76
77
# File 'lib/minitwin/class_methods/rbs.rb', line 71

def rbs_elem_type_for(meta)
  if meta[:element_twin]
    rbs_class_name(meta[:element_twin])
  else
    "untyped"
  end
end

#rbs_type_for(meta) ⇒ Object

Parameters:

  • meta (Object)

Returns:

  • (Object)


61
62
63
64
65
66
67
68
69
# File 'lib/minitwin/class_methods/rbs.rb', line 61

def rbs_type_for(meta)
  if meta[:twin]
    rbs_class_name(meta[:twin])
  elsif meta[:nested_class]
    rbs_class_name(meta[:nested_class])
  else
    dry_type_to_rbs(meta[:type])
  end
end

#to_rbsString

: () -> String

Returns:

  • (String)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/minitwin/class_methods/rbs.rb', line 9

def to_rbs
  # :nocov:
  return "" unless name

  lines = []
  superclass_name = superclass ? " < ::#{superclass.name}" : ""
  # :nocov:
  lines << "class ::#{name}#{superclass_name}"

  # Collect initializer parameters
  init_params = []

  props = properties
  props.each do |prop, meta|
    as_meta = meta[:as]
    # Dynamic aliases (Proc) cannot be represented statically in RBS;
    # fall back to the base property name.
    reader_name = as_meta && !as_meta.is_a?(Proc) && as_meta != prop ? as_meta : prop
    type = rbs_type_for(meta)
    lines << "  attr_reader #{reader_name}: #{type}"
    if method_defined?(:"#{prop}=", false)
      # :nocov:
      lines << "  attr_writer #{prop}: #{type}"
      # :nocov:
    end

    # Add to initializer parameters (all optional)
    init_params << "?#{prop}: #{type}"
  end

  collections.each do |name_sym, meta|
    elem_type = rbs_elem_type_for(meta)
    lines << "  attr_accessor #{name_sym}: ::Array[#{elem_type}]"

    # Add to initializer parameters (all optional, collections accept arrays or individual items)
    init_params << "?#{name_sym}: ::Array[#{elem_type}]"
  end

  # Add initializer signature
  lines << ""
  lines << if init_params.any?
             "  def initialize: (#{init_params.join(", ")}, **untyped) -> void"
           else
             "  def initialize: (**untyped) -> void"
           end

  lines << "end"
  lines.join("\n")
end