# frozen_string_literal: true module Runger module RBSGenerator TYPE_TO_CLASS = { string: 'String', integer: 'Integer', float: 'Float', date: 'Date', datetime: 'DateTime', uri: 'URI', boolean: 'bool', }.freeze # Generate RBS signature from a config class def to_rbs *namespace, class_name = name.split('::') buf = [] indent = 0 interface_name = '_Config' if namespace.empty? interface_name = "_#{class_name}" else buf << "module #{namespace.join('::')}" indent += 1 end # Using interface emulates a module we include to provide getters and setters # (thus making `super` possible) buf << "#{' ' * indent}interface #{interface_name}" indent += 1 # Generating setters and getters for config attributes config_attributes.each do |param| type = coercion_mapping[param] || defaults[param.to_s] type = case type in NilClass 'untyped' in Symbol TYPE_TO_CLASS.fetch(type) { defaults[param] ? 'Symbol' : 'untyped' } in Array 'Array[untyped]' in array: _, type:, **nil "Array[#{TYPE_TO_CLASS.fetch(type, 'untyped')}]" in Hash 'Hash[string,untyped]' in TrueClass | FalseClass 'bool' else type.class.to_s end getter_type = type getter_type = "#{type}?" unless required_attributes.include?(param) buf << "#{' ' * indent}def #{param}: () -> #{getter_type}" buf << "#{' ' * indent}def #{param}=: (#{type}) -> void" if ['bool', 'bool?'].include?(type) buf << "#{' ' * indent}def #{param}?: () -> #{getter_type}" end end indent -= 1 buf << "#{' ' * indent}end" buf << '' buf << "#{' ' * indent}class #{class_name} < #{superclass.name}" indent += 1 buf << "#{' ' * indent}include #{interface_name}" indent -= 1 buf << "#{' ' * indent}end" unless namespace.empty? buf << 'end' end buf << '' buf.join("\n") end end Config.extend(RBSGenerator) end