# RBS Rails current state and the future This document describes the design of `rbs_rails` gem, and the future works. It also describes Rails-related gems' RBS files in ruby/gem_rbs_collection repository. ## RBS files in gem_rbs_collection ### work with RBS Rails Some classes, modules, and interfaces are depend on RBS Rails. Be careful to introduce breaking changes to them. ### Generated RBS files Currently this repository contains generated and hand-written RBS files. I want to distinguish them to run the generator continuously, but unfortunately they are mixed. In the future, probably unifying these files is better. We do not need to distinguish generated and hand-written files. But probably we need to distinguish `patch.rbs` because the `patch.rbs` file contains RBS that is not for the gem itself, but other dependencies. ### Public API and Private API As I mentioned the previous section, the RBS files are generated. They contain not only public APIs but also private APIs. I think we can drop RBS definitions for private APIs. They are unnecessary information for Rails user. They also make the RBS file larger. We can keep the RBS files slim by removing unnecessary definitions. I'm concerning that some private APIs are actually used by the user... Probably we need to leave some private API. ## Design This section describes the design of RBS Rails gem. ### Rails related gems Such as action_args. * RBS Rails does not support such gems * If it supports unofficial gems, the maintenance cost will increase * Probably plug-in system is a good approach for this problem. * I've not considered that RBS Rails should treat official but non-default gems, such as jbuilder, propshaft, and so on. * Not all users use the feature, so plug-in is appropriate...? * Perhaps RBS Rails does not need to support them if they do not have meta-programming feature such as dynamic method generation. ### RBS Rails generates valid standalone RBSs The generated RBS files by RBS Rails should be valid only with the Rails related RBS files in ruby/gem_rbs_collection. It means the user does not need to write RBS definition to make the generated RBS valid. "valid" means `rbs validate` command passes ### Generate RBS as a String RBS Rails construct RBS content as a String. We can also construct with RBS AST, but I think it is over-engineering. String construction is enough in this case. But probably it should escape correctly, such as method name. Probably we can solve this problem with using `RBS::Writer` partially. ## Future This section describes what I want to achieve by RBS Rails in the future. ### Define methods in right places Currently, the generated method is defined in a pseudo module. It introduces some problems, so we should define these method in the right places. ### path helper I didn't focus on it. Currently RBS Rails generates type definitions for path helpers, but actually it is not utilized. Probably we can improve it. ### How to fetch metadata from Rails Currently, RBS Rails fetches metadata with two ways. They are static and dynamic analysis. In short, we should remove static analysis because it is incomplete. For example, currently RBS Rails uses static analysis to get enum metadata. https://github.com/pocke/rbs_rails/blob/4ba3f0fa61f961590213cc04e83a5433166691ed/lib/rbs_rails/active_record.rb#L356-L359 It's because Rails does not store enough information to construct the RBS definitions. But the static analysis has a problem. It does not work on `enum` definitions in another files. For example: ```ruby # publishable.rb module Publishable extend AS::Concern included do enum state: { draft: 1, published: 2 } end end # note.rb class Note < ApplicationRecord include Publishable end ``` In the above case, RBS Rails does not detect `state` enum because RBS Rails only parse `note.rb` but the enum defined in `publishable.rb`. To solve this problem, I think we need to introduce dynamic analysis with different approach with other features. We can add a module to override tne `enum` method. For example: ```ruby module EnumInspection def enum(entry) store_the_enum_entry entry super end end ActiveRecord::Base.singleton_class.prepend EnumInspection ``` It can use the data that `enum` method received, so it has enough information to generate RBS definitions. It also depends only on public APIs, so it is stable. However, I'm concerning that there is a right timing to prepend the module. This module should be prepended before evaluating all user defined code. Perhaps we can replace other dynamic analysis with this solution. Such as `has_many`. I think the prepending solution is better if the dynamic analysis depends on a Rails private API. We need to research that RBS Rails depends on private APIs or not. ## References * https://github.com/pocke/rbs_rails/blob/4ba3f0fa61f961590213cc04e83a5433166691ed/DESIGN.md