tapioca 0.4.10 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -2
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +38 -39
- data/lib/tapioca/compilers/dsl/action_mailer.rb +4 -4
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +80 -48
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +60 -65
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +27 -23
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +18 -17
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +8 -7
- data/lib/tapioca/compilers/dsl/active_resource.rb +5 -4
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +6 -7
- data/lib/tapioca/compilers/dsl/base.rb +1 -1
- data/lib/tapioca/compilers/dsl/frozen_record.rb +25 -25
- data/lib/tapioca/compilers/dsl/{active_record_identity_cache.rb → identity_cache.rb} +11 -10
- data/lib/tapioca/compilers/dsl/protobuf.rb +1 -1
- data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +83 -0
- data/lib/tapioca/compilers/dsl/smart_properties.rb +1 -1
- data/lib/tapioca/compilers/dsl/state_machines.rb +75 -73
- data/lib/tapioca/compilers/dsl/url_helpers.rb +9 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +69 -40
- data/lib/tapioca/gemfile.rb +30 -22
- data/lib/tapioca/generator.rb +4 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +18 -3
| @@ -15,7 +15,7 @@ module Tapioca | |
| 15 15 | 
             
              module Compilers
         | 
| 16 16 | 
             
                module Dsl
         | 
| 17 17 | 
             
                  # `Tapioca::Compilers::Dsl::SmartProperties` generates RBI files for classes that include
         | 
| 18 | 
            -
                  # `SmartProperties` | 
| 18 | 
            +
                  # [`SmartProperties`](https://github.com/t6d/smart_properties).
         | 
| 19 19 | 
             
                  #
         | 
| 20 20 | 
             
                  # For example, with the following class that includes `SmartProperties`:
         | 
| 21 21 | 
             
                  #
         | 
| @@ -15,10 +15,12 @@ end | |
| 15 15 | 
             
            module Tapioca
         | 
| 16 16 | 
             
              module Compilers
         | 
| 17 17 | 
             
                module Dsl
         | 
| 18 | 
            -
                  # ` | 
| 19 | 
            -
                  # ( | 
| 20 | 
            -
                  # methods generated by | 
| 21 | 
            -
                  #  | 
| 18 | 
            +
                  # `Tapioca::Compilers::Dsl::StateMachines` generates RBI files for classes that setup a
         | 
| 19 | 
            +
                  # [`state_machine`](https://github.com/state-machines/state_machines). The generator also
         | 
| 20 | 
            +
                  # processes the extra methods generated by
         | 
| 21 | 
            +
                  # [StateMachines Active Record](https://github.com/state-machines/state_machines-activerecord)
         | 
| 22 | 
            +
                  # and [StateMachines Active Model](https://github.com/state-machines/state_machines-activemodel)
         | 
| 23 | 
            +
                  # integrations.
         | 
| 22 24 | 
             
                  #
         | 
| 23 25 | 
             
                  # For example, with the following `Vehicle` class:
         | 
| 24 26 | 
             
                  #
         | 
| @@ -45,75 +47,75 @@ module Tapioca | |
| 45 47 | 
             
                  # # vehicle.rbi
         | 
| 46 48 | 
             
                  # # typed: true
         | 
| 47 49 | 
             
                  # class Vehicle
         | 
| 48 | 
            -
                  #   include  | 
| 49 | 
            -
                  #   extend  | 
| 50 | 
            -
                  # end
         | 
| 50 | 
            +
                  #   include StateMachineInstanceHelperModule
         | 
| 51 | 
            +
                  #   extend StateMachineClassHelperModule
         | 
| 51 52 | 
             
                  #
         | 
| 52 | 
            -
                  # | 
| 53 | 
            -
                  # | 
| 54 | 
            -
                  # | 
| 53 | 
            +
                  #   module StateMachineClassHelperModule
         | 
| 54 | 
            +
                  #     sig { params(event: T.any(String, Symbol)).returns(String) }
         | 
| 55 | 
            +
                  #     def human_alarm_state_event_name(event); end
         | 
| 55 56 | 
             
                  #
         | 
| 56 | 
            -
                  # | 
| 57 | 
            -
                  # | 
| 58 | 
            -
                  # | 
| 57 | 
            +
                  #     sig { params(state: T.any(String, Symbol)).returns(String) }
         | 
| 58 | 
            +
                  #     def human_alarm_state_name(state); end
         | 
| 59 | 
            +
                  #   end
         | 
| 59 60 | 
             
                  #
         | 
| 60 | 
            -
                  # | 
| 61 | 
            -
                  # | 
| 62 | 
            -
                  # | 
| 61 | 
            +
                  #   module StateMachineInstanceHelperModule
         | 
| 62 | 
            +
                  #     sig { returns(T::Boolean) }
         | 
| 63 | 
            +
                  #     def alarm_active?; end
         | 
| 63 64 | 
             
                  #
         | 
| 64 | 
            -
                  # | 
| 65 | 
            -
                  # | 
| 65 | 
            +
                  #     sig { returns(T::Boolean) }
         | 
| 66 | 
            +
                  #     def alarm_off?; end
         | 
| 66 67 | 
             
                  #
         | 
| 67 | 
            -
                  # | 
| 68 | 
            -
                  # | 
| 68 | 
            +
                  #     sig { returns(Integer) }
         | 
| 69 | 
            +
                  #     def alarm_state; end
         | 
| 69 70 | 
             
                  #
         | 
| 70 | 
            -
                  # | 
| 71 | 
            -
                  # | 
| 71 | 
            +
                  #     sig { params(value: Integer).returns(Integer) }
         | 
| 72 | 
            +
                  #     def alarm_state=(value); end
         | 
| 72 73 | 
             
                  #
         | 
| 73 | 
            -
                  # | 
| 74 | 
            -
                  # | 
| 74 | 
            +
                  #     sig { params(state: T.any(String, Symbol)).returns(T::Boolean) }
         | 
| 75 | 
            +
                  #     def alarm_state?(state); end
         | 
| 75 76 | 
             
                  #
         | 
| 76 | 
            -
                  # | 
| 77 | 
            -
                  # | 
| 77 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Array[T.any(String, Symbol)]) }
         | 
| 78 | 
            +
                  #     def alarm_state_events(*args); end
         | 
| 78 79 | 
             
                  #
         | 
| 79 | 
            -
                  # | 
| 80 | 
            -
                  # | 
| 80 | 
            +
                  #     sig { returns(T.any(String, Symbol)) }
         | 
| 81 | 
            +
                  #     def alarm_state_name; end
         | 
| 81 82 | 
             
                  #
         | 
| 82 | 
            -
                  # | 
| 83 | 
            -
                  # | 
| 83 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Array[::StateMachines::Transition]) }
         | 
| 84 | 
            +
                  #     def alarm_state_paths(*args); end
         | 
| 84 85 | 
             
                  #
         | 
| 85 | 
            -
                  # | 
| 86 | 
            -
                  # | 
| 86 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Array[::StateMachines::Transition]) }
         | 
| 87 | 
            +
                  #     def alarm_state_transitions(*args); end
         | 
| 87 88 | 
             
                  #
         | 
| 88 | 
            -
                  # | 
| 89 | 
            -
                  # | 
| 89 | 
            +
                  #     sig { returns(T::Boolean) }
         | 
| 90 | 
            +
                  #     def can_disable_alarm?; end
         | 
| 90 91 | 
             
                  #
         | 
| 91 | 
            -
                  # | 
| 92 | 
            -
                  # | 
| 92 | 
            +
                  #     sig { returns(T::Boolean) }
         | 
| 93 | 
            +
                  #     def can_enable_alarm?; end
         | 
| 93 94 | 
             
                  #
         | 
| 94 | 
            -
                  # | 
| 95 | 
            -
                  # | 
| 95 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Boolean) }
         | 
| 96 | 
            +
                  #     def disable_alarm(*args); end
         | 
| 96 97 | 
             
                  #
         | 
| 97 | 
            -
                  # | 
| 98 | 
            -
                  # | 
| 98 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Boolean) }
         | 
| 99 | 
            +
                  #     def disable_alarm!(*args); end
         | 
| 99 100 | 
             
                  #
         | 
| 100 | 
            -
                  # | 
| 101 | 
            -
                  # | 
| 101 | 
            +
                  #     sig { params(args: T.untyped).returns(T.nilable(::StateMachines::Transition)) }
         | 
| 102 | 
            +
                  #     def disable_alarm_transition(*args); end
         | 
| 102 103 | 
             
                  #
         | 
| 103 | 
            -
                  # | 
| 104 | 
            -
                  # | 
| 104 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Boolean) }
         | 
| 105 | 
            +
                  #     def enable_alarm(*args); end
         | 
| 105 106 | 
             
                  #
         | 
| 106 | 
            -
                  # | 
| 107 | 
            -
                  # | 
| 107 | 
            +
                  #     sig { params(args: T.untyped).returns(T::Boolean) }
         | 
| 108 | 
            +
                  #     def enable_alarm!(*args); end
         | 
| 108 109 | 
             
                  #
         | 
| 109 | 
            -
                  # | 
| 110 | 
            -
                  # | 
| 110 | 
            +
                  #     sig { params(args: T.untyped).returns(T.nilable(::StateMachines::Transition)) }
         | 
| 111 | 
            +
                  #     def enable_alarm_transition(*args); end
         | 
| 111 112 | 
             
                  #
         | 
| 112 | 
            -
                  # | 
| 113 | 
            -
                  # | 
| 113 | 
            +
                  #     sig { params(event: T.any(String, Symbol), args: T.untyped).returns(T::Boolean) }
         | 
| 114 | 
            +
                  #     def fire_alarm_state_event(event, *args); end
         | 
| 114 115 | 
             
                  #
         | 
| 115 | 
            -
                  # | 
| 116 | 
            -
                  # | 
| 116 | 
            +
                  #     sig { returns(String) }
         | 
| 117 | 
            +
                  #     def human_alarm_state_name; end
         | 
| 118 | 
            +
                  #   end
         | 
| 117 119 | 
             
                  # end
         | 
| 118 120 | 
             
                  # ~~~
         | 
| 119 121 | 
             
                  class StateMachines < Base
         | 
| @@ -123,34 +125,34 @@ module Tapioca | |
| 123 125 | 
             
                    def decorate(root, constant)
         | 
| 124 126 | 
             
                      return if constant.state_machines.empty?
         | 
| 125 127 |  | 
| 126 | 
            -
                       | 
| 127 | 
            -
             | 
| 128 | 
            +
                      root.path(constant) do |klass|
         | 
| 129 | 
            +
                        instance_module_name = "StateMachineInstanceHelperModule"
         | 
| 130 | 
            +
                        class_module_name = "StateMachineClassHelperModule"
         | 
| 128 131 |  | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 132 | 
            +
                        instance_module = klass.create_module(instance_module_name)
         | 
| 133 | 
            +
                        class_module = klass.create_module(class_module_name)
         | 
| 131 134 |  | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 135 | 
            +
                        constant.state_machines.each_value do |machine|
         | 
| 136 | 
            +
                          state_type = state_type_for(machine)
         | 
| 134 137 |  | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 138 | 
            +
                          define_state_accessor(instance_module, machine, state_type)
         | 
| 139 | 
            +
                          define_state_predicate(instance_module, machine)
         | 
| 140 | 
            +
                          define_event_helpers(instance_module, machine)
         | 
| 141 | 
            +
                          define_path_helpers(instance_module, machine)
         | 
| 142 | 
            +
                          define_name_helpers(instance_module, class_module, machine)
         | 
| 143 | 
            +
                          define_scopes(class_module, machine)
         | 
| 141 144 |  | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            +
                          define_state_methods(instance_module, machine)
         | 
| 146 | 
            +
                          define_event_methods(instance_module, machine)
         | 
| 147 | 
            +
                        end
         | 
| 145 148 |  | 
| 146 | 
            -
             | 
| 149 | 
            +
                        matching_integration_name = ::StateMachines::Integrations.match(constant)&.integration_name
         | 
| 147 150 |  | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 151 | 
            +
                        case matching_integration_name
         | 
| 152 | 
            +
                        when :active_record
         | 
| 153 | 
            +
                          define_activerecord_methods(instance_module)
         | 
| 154 | 
            +
                        end
         | 
| 152 155 |  | 
| 153 | 
            -
                      root.path(constant) do |klass|
         | 
| 154 156 | 
             
                        klass.create_include(instance_module_name)
         | 
| 155 157 | 
             
                        klass.create_extend(class_module_name)
         | 
| 156 158 | 
             
                      end
         | 
| @@ -15,8 +15,7 @@ module Tapioca | |
| 15 15 | 
             
              module Compilers
         | 
| 16 16 | 
             
                module Dsl
         | 
| 17 17 | 
             
                  # `Tapioca::Compilers::Dsl::UrlHelpers` generates RBI files for classes that include or extend
         | 
| 18 | 
            -
                  # `Rails.application.routes.url_helpers`
         | 
| 19 | 
            -
                  # (see https://api.rubyonrails.org/v5.1.7/classes/ActionDispatch/Routing/UrlFor.html#module-ActionDispatch::Routing::UrlFor-label-URL+generation+for+named+routes).
         | 
| 18 | 
            +
                  # [`Rails.application.routes.url_helpers`](https://api.rubyonrails.org/v5.1.7/classes/ActionDispatch/Routing/UrlFor.html#module-ActionDispatch::Routing::UrlFor-label-URL+generation+for+named+routes).
         | 
| 20 19 | 
             
                  #
         | 
| 21 20 | 
             
                  # For example, with the following setup:
         | 
| 22 21 | 
             
                  #
         | 
| @@ -32,7 +31,12 @@ module Tapioca | |
| 32 31 | 
             
                  # ~~~rb
         | 
| 33 32 | 
             
                  # app/models/post.rb
         | 
| 34 33 | 
             
                  # class Post
         | 
| 35 | 
            -
                  #    | 
| 34 | 
            +
                  #   # Use `T.unsafe` so that Sorbet does not complain about a dynamic
         | 
| 35 | 
            +
                  #   # module being included. This allows the `include` to happen properly
         | 
| 36 | 
            +
                  #   # at runtime but Sorbet won't see the include. However, since this
         | 
| 37 | 
            +
                  #   # generator will generate the proper RBI files for the include,
         | 
| 38 | 
            +
                  #   # static type checking will work as expected.
         | 
| 39 | 
            +
                  #   T.unsafe(self).include Rails.application.routes.url_helpers
         | 
| 36 40 | 
             
                  # end
         | 
| 37 41 | 
             
                  # ~~~
         | 
| 38 42 | 
             
                  #
         | 
| @@ -126,8 +130,8 @@ module Tapioca | |
| 126 130 | 
             
                    sig { params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(Module)).void }
         | 
| 127 131 | 
             
                    def generate_module_for(root, constant)
         | 
| 128 132 | 
             
                      root.create_module(T.must(constant.name)) do |mod|
         | 
| 129 | 
            -
                        mod.create_include("ActionDispatch::Routing::UrlFor")
         | 
| 130 | 
            -
                        mod.create_include("ActionDispatch::Routing::PolymorphicRoutes")
         | 
| 133 | 
            +
                        mod.create_include("::ActionDispatch::Routing::UrlFor")
         | 
| 134 | 
            +
                        mod.create_include("::ActionDispatch::Routing::PolymorphicRoutes")
         | 
| 131 135 |  | 
| 132 136 | 
             
                        constant.instance_methods(false).each do |method|
         | 
| 133 137 | 
             
                          mod.create_method(
         | 
| @@ -74,9 +74,9 @@ module Tapioca | |
| 74 74 | 
             
                      compile(symbol, constant)
         | 
| 75 75 | 
             
                    end
         | 
| 76 76 |  | 
| 77 | 
            -
                    sig { params(symbol: String).returns(BasicObject).checked(:never) }
         | 
| 78 | 
            -
                    def resolve_constant(symbol)
         | 
| 79 | 
            -
                      Object.const_get(symbol,  | 
| 77 | 
            +
                    sig { params(symbol: String, inherit: T::Boolean).returns(BasicObject).checked(:never) }
         | 
| 78 | 
            +
                    def resolve_constant(symbol, inherit: false)
         | 
| 79 | 
            +
                      Object.const_get(symbol, inherit)
         | 
| 80 80 | 
             
                    rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
         | 
| 81 81 | 
             
                      nil
         | 
| 82 82 | 
             
                    end
         | 
| @@ -122,12 +122,15 @@ module Tapioca | |
| 122 122 | 
             
                    def compile_alias(name, constant)
         | 
| 123 123 | 
             
                      return if symbol_ignored?(name)
         | 
| 124 124 |  | 
| 125 | 
            -
                       | 
| 125 | 
            +
                      target = name_of(constant)
         | 
| 126 | 
            +
                      # If target has no name, let's make it an anonymous class or module with `Class.new` or `Module.new`
         | 
| 127 | 
            +
                      target = "#{constant.class}.new" unless target
         | 
| 128 | 
            +
             | 
| 126 129 | 
             
                      add_to_alias_namespace(name)
         | 
| 127 130 |  | 
| 128 131 | 
             
                      return if IGNORED_SYMBOLS.include?(name)
         | 
| 129 132 |  | 
| 130 | 
            -
                      indented("#{name} = #{ | 
| 133 | 
            +
                      indented("#{name} = #{target}")
         | 
| 131 134 | 
             
                    end
         | 
| 132 135 |  | 
| 133 136 | 
             
                    sig do
         | 
| @@ -189,15 +192,12 @@ module Tapioca | |
| 189 192 | 
             
                    def compile_module_helpers(constant)
         | 
| 190 193 | 
             
                      abstract_type = T::Private::Abstract::Data.get(constant, :abstract_type)
         | 
| 191 194 |  | 
| 192 | 
            -
                       | 
| 193 | 
            -
             | 
| 194 | 
            -
                       | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
                      else
         | 
| 199 | 
            -
                        ""
         | 
| 200 | 
            -
                      end
         | 
| 195 | 
            +
                      helpers = []
         | 
| 196 | 
            +
                      helpers << indented("#{abstract_type}!") if abstract_type
         | 
| 197 | 
            +
                      helpers << indented("final!") if T::Private::Final.final_module?(constant)
         | 
| 198 | 
            +
                      helpers << indented("sealed!") if T::Private::Sealed.sealed_module?(constant)
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                      helpers.join("\n")
         | 
| 201 201 | 
             
                    end
         | 
| 202 202 |  | 
| 203 203 | 
             
                    sig { params(constant: Module).returns(String) }
         | 
| @@ -207,7 +207,7 @@ module Tapioca | |
| 207 207 | 
             
                      constant.props.map do |name, prop|
         | 
| 208 208 | 
             
                        method = "prop"
         | 
| 209 209 | 
             
                        method = "const" if prop.fetch(:immutable, false)
         | 
| 210 | 
            -
                        type = prop.fetch(:type_object, "T.untyped")
         | 
| 210 | 
            +
                        type = prop.fetch(:type_object, "T.untyped").to_s.gsub(".returns(<VOID>)", ".void")
         | 
| 211 211 |  | 
| 212 212 | 
             
                        if prop.key?(:default)
         | 
| 213 213 | 
             
                          indented("#{method} :#{name}, #{type}, default: T.unsafe(nil)")
         | 
| @@ -292,33 +292,16 @@ module Tapioca | |
| 292 292 |  | 
| 293 293 | 
             
                    sig { params(constant: Module).returns(String) }
         | 
| 294 294 | 
             
                    def compile_mixins(constant)
         | 
| 295 | 
            -
                       | 
| 296 | 
            -
                        if constant.is_a?(Class)
         | 
| 297 | 
            -
                          ancestors = constant.superclass&.ancestors || Object.ancestors
         | 
| 298 | 
            -
                          Set.new(ancestors)
         | 
| 299 | 
            -
                        else
         | 
| 300 | 
            -
                          Module.ancestors
         | 
| 301 | 
            -
                        end
         | 
| 295 | 
            +
                      singleton_class = singleton_class_of(constant)
         | 
| 302 296 |  | 
| 303 | 
            -
                       | 
| 304 | 
            -
             | 
| 305 | 
            -
                          Set.new(singleton_class_of(constant.superclass).ancestors)
         | 
| 306 | 
            -
                        else
         | 
| 307 | 
            -
                          Module.ancestors
         | 
| 308 | 
            -
                        end
         | 
| 309 | 
            -
             | 
| 310 | 
            -
                      interesting_ancestors =
         | 
| 311 | 
            -
                        constant.ancestors.reject { |mod| ignorable_ancestors.include?(mod) }
         | 
| 297 | 
            +
                      interesting_ancestors = interesting_ancestors_of(constant)
         | 
| 298 | 
            +
                      interesting_singleton_class_ancestors = interesting_ancestors_of(singleton_class)
         | 
| 312 299 |  | 
| 313 300 | 
             
                      prepend = interesting_ancestors.take_while { |c| !are_equal?(constant, c) }
         | 
| 314 301 | 
             
                      include = interesting_ancestors.drop(prepend.size + 1)
         | 
| 315 | 
            -
                      extend  =  | 
| 316 | 
            -
                         | 
| 317 | 
            -
             | 
| 318 | 
            -
                            inherited_singleton_class_ancestors.include?(mod) ||
         | 
| 319 | 
            -
                            !public_module?(mod) ||
         | 
| 320 | 
            -
                            Module != class_of(mod)
         | 
| 321 | 
            -
                        end
         | 
| 302 | 
            +
                      extend  = interesting_singleton_class_ancestors.reject do |mod|
         | 
| 303 | 
            +
                        !public_module?(mod) || Module != class_of(mod) || are_equal?(mod, singleton_class)
         | 
| 304 | 
            +
                      end
         | 
| 322 305 |  | 
| 323 306 | 
             
                      prepends = prepend
         | 
| 324 307 | 
             
                        .reverse
         | 
| @@ -757,18 +740,59 @@ module Tapioca | |
| 757 740 | 
             
                      Module.instance_method(:name).bind(constant).call
         | 
| 758 741 | 
             
                    end
         | 
| 759 742 |  | 
| 760 | 
            -
                    sig { params(constant:  | 
| 743 | 
            +
                    sig { params(constant: Module).returns(Class) }
         | 
| 761 744 | 
             
                    def singleton_class_of(constant)
         | 
| 762 745 | 
             
                      Object.instance_method(:singleton_class).bind(constant).call
         | 
| 763 746 | 
             
                    end
         | 
| 764 747 |  | 
| 748 | 
            +
                    sig { params(constant: Module).returns(T::Array[Module]) }
         | 
| 749 | 
            +
                    def ancestors_of(constant)
         | 
| 750 | 
            +
                      Module.instance_method(:ancestors).bind(constant).call
         | 
| 751 | 
            +
                    end
         | 
| 752 | 
            +
             | 
| 753 | 
            +
                    sig { params(constant: Module).returns(T::Array[Module]) }
         | 
| 754 | 
            +
                    def inherited_ancestors_of(constant)
         | 
| 755 | 
            +
                      if Class === constant
         | 
| 756 | 
            +
                        ancestors_of(superclass_of(constant) || Object)
         | 
| 757 | 
            +
                      else
         | 
| 758 | 
            +
                        Module.ancestors
         | 
| 759 | 
            +
                      end
         | 
| 760 | 
            +
                    end
         | 
| 761 | 
            +
             | 
| 762 | 
            +
                    sig { params(constant: Module).returns(T::Array[Module]) }
         | 
| 763 | 
            +
                    def interesting_ancestors_of(constant)
         | 
| 764 | 
            +
                      inherited_ancestors_ids = Set.new(
         | 
| 765 | 
            +
                        inherited_ancestors_of(constant).map { |mod| object_id_of(mod) }
         | 
| 766 | 
            +
                      )
         | 
| 767 | 
            +
                      # TODO: There is actually a bug here where this will drop modules that
         | 
| 768 | 
            +
                      # may be included twice. For example:
         | 
| 769 | 
            +
                      #
         | 
| 770 | 
            +
                      # ```ruby
         | 
| 771 | 
            +
                      # class Foo
         | 
| 772 | 
            +
                      #   prepend Kernel
         | 
| 773 | 
            +
                      # end
         | 
| 774 | 
            +
                      # ````
         | 
| 775 | 
            +
                      # would give:
         | 
| 776 | 
            +
                      # ```ruby
         | 
| 777 | 
            +
                      # Foo.ancestors #=> [Kernel, Foo, Object, Kernel, BasicObject]
         | 
| 778 | 
            +
                      # ````
         | 
| 779 | 
            +
                      # but since we drop `Kernel` whenever we match it, we would miss
         | 
| 780 | 
            +
                      # the `prepend Kernel` in the output.
         | 
| 781 | 
            +
                      #
         | 
| 782 | 
            +
                      # Instead, we should only drop the tail matches of the ancestors and
         | 
| 783 | 
            +
                      # inherited ancestors, past the location of the constant itself.
         | 
| 784 | 
            +
                      constant.ancestors.reject do |mod|
         | 
| 785 | 
            +
                        inherited_ancestors_ids.include?(object_id_of(mod))
         | 
| 786 | 
            +
                      end
         | 
| 787 | 
            +
                    end
         | 
| 788 | 
            +
             | 
| 765 789 | 
             
                    sig { params(constant: Module).returns(T.nilable(String)) }
         | 
| 766 790 | 
             
                    def name_of(constant)
         | 
| 767 791 | 
             
                      name = name_of_proxy_target(constant)
         | 
| 768 792 | 
             
                      return name if name
         | 
| 769 793 | 
             
                      name = raw_name_of(constant)
         | 
| 770 794 | 
             
                      return if name.nil?
         | 
| 771 | 
            -
                      return unless are_equal?(constant, resolve_constant(name))
         | 
| 795 | 
            +
                      return unless are_equal?(constant, resolve_constant(name, inherit: true))
         | 
| 772 796 | 
             
                      name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
         | 
| 773 797 | 
             
                      name
         | 
| 774 798 | 
             
                    end
         | 
| @@ -817,6 +841,11 @@ module Tapioca | |
| 817 841 | 
             
                      constant.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
         | 
| 818 842 | 
             
                    end
         | 
| 819 843 |  | 
| 844 | 
            +
                    sig { params(object: Object).returns(T::Boolean).checked(:never) }
         | 
| 845 | 
            +
                    def object_id_of(object)
         | 
| 846 | 
            +
                      Object.instance_method(:object_id).bind(object).call
         | 
| 847 | 
            +
                    end
         | 
| 848 | 
            +
             | 
| 820 849 | 
             
                    sig { params(constant: Module, other: BasicObject).returns(T::Boolean).checked(:never) }
         | 
| 821 850 | 
             
                    def are_equal?(constant, other)
         | 
| 822 851 | 
             
                      BasicObject.instance_method(:equal?).bind(constant).call(other)
         | 
    
        data/lib/tapioca/gemfile.rb
    CHANGED
    
    | @@ -17,27 +17,23 @@ module Tapioca | |
| 17 17 | 
             
                  )
         | 
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 | 
            +
                sig { returns(Bundler::Definition) }
         | 
| 21 | 
            +
                attr_reader(:definition)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                sig { returns(T::Array[Gem]) }
         | 
| 24 | 
            +
                attr_reader(:dependencies)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                sig { returns(T::Array[String]) }
         | 
| 27 | 
            +
                attr_reader(:missing_specs)
         | 
| 28 | 
            +
             | 
| 20 29 | 
             
                sig { void }
         | 
| 21 30 | 
             
                def initialize
         | 
| 22 31 | 
             
                  @gemfile = T.let(File.new(Bundler.default_gemfile), File)
         | 
| 23 32 | 
             
                  @lockfile = T.let(File.new(Bundler.default_lockfile), File)
         | 
| 24 | 
            -
                  @ | 
| 25 | 
            -
                   | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
                sig { returns(T::Array[Gem]) }
         | 
| 29 | 
            -
                def dependencies
         | 
| 30 | 
            -
                  @dependencies ||= begin
         | 
| 31 | 
            -
                    specs = definition.locked_gems.specs.to_a
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                    definition
         | 
| 34 | 
            -
                      .resolve
         | 
| 35 | 
            -
                      .materialize(specs)
         | 
| 36 | 
            -
                      .map { |spec| Gem.new(spec) }
         | 
| 37 | 
            -
                      .reject { |gem| gem.ignore?(dir) }
         | 
| 38 | 
            -
                      .uniq(&:rbi_file_name)
         | 
| 39 | 
            -
                      .sort_by(&:rbi_file_name)
         | 
| 40 | 
            -
                  end
         | 
| 33 | 
            +
                  @definition = T.let(Bundler::Dsl.evaluate(gemfile, lockfile, {}), Bundler::Definition)
         | 
| 34 | 
            +
                  dependencies, missing_specs = load_dependencies
         | 
| 35 | 
            +
                  @dependencies = T.let(dependencies, T::Array[Gem])
         | 
| 36 | 
            +
                  @missing_specs = T.let(missing_specs, T::Array[String])
         | 
| 41 37 | 
             
                end
         | 
| 42 38 |  | 
| 43 39 | 
             
                sig { params(gem_name: String).returns(T.nilable(Gem)) }
         | 
| @@ -55,6 +51,23 @@ module Tapioca | |
| 55 51 | 
             
                sig { returns(File) }
         | 
| 56 52 | 
             
                attr_reader(:gemfile, :lockfile)
         | 
| 57 53 |  | 
| 54 | 
            +
                sig { returns([T::Array[Gem], T::Array[String]]) }
         | 
| 55 | 
            +
                def load_dependencies
         | 
| 56 | 
            +
                  deps = definition.locked_gems.dependencies.values
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  missing_specs = T::Array[String].new
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  dependencies = definition
         | 
| 61 | 
            +
                    .resolve
         | 
| 62 | 
            +
                    .materialize(deps, missing_specs)
         | 
| 63 | 
            +
                    .map { |spec| Gem.new(spec) }
         | 
| 64 | 
            +
                    .reject { |gem| gem.ignore?(dir) }
         | 
| 65 | 
            +
                    .uniq(&:rbi_file_name)
         | 
| 66 | 
            +
                    .sort_by(&:rbi_file_name)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  [dependencies, missing_specs]
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 58 71 | 
             
                sig { returns(Bundler::Runtime) }
         | 
| 59 72 | 
             
                def runtime
         | 
| 60 73 | 
             
                  Bundler::Runtime.new(File.dirname(gemfile.path), definition)
         | 
| @@ -65,11 +78,6 @@ module Tapioca | |
| 65 78 | 
             
                  definition.groups
         | 
| 66 79 | 
             
                end
         | 
| 67 80 |  | 
| 68 | 
            -
                sig { returns(Bundler::Definition) }
         | 
| 69 | 
            -
                def definition
         | 
| 70 | 
            -
                  @definition ||= Bundler::Dsl.evaluate(gemfile, lockfile, {})
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
             | 
| 73 81 | 
             
                sig { returns(String) }
         | 
| 74 82 | 
             
                def dir
         | 
| 75 83 | 
             
                  File.expand_path(gemfile.path + "/..")
         |