tapioca 0.4.3 → 0.4.8
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 -0
- data/README.md +7 -5
- data/Rakefile +1 -0
- data/lib/tapioca/cli.rb +9 -2
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +1 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +10 -28
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +25 -8
- data/lib/tapioca/compilers/dsl/active_record_identity_cache.rb +3 -4
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +1 -1
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +0 -2
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +1 -1
- data/lib/tapioca/compilers/dsl/base.rb +14 -10
- data/lib/tapioca/compilers/dsl/protobuf.rb +8 -8
- data/lib/tapioca/compilers/dsl/url_helpers.rb +68 -0
- data/lib/tapioca/compilers/dsl_compiler.rb +5 -5
- data/lib/tapioca/compilers/requires_compiler.rb +37 -9
- data/lib/tapioca/compilers/sorbet.rb +1 -1
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +57 -24
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +1 -1
- data/lib/tapioca/compilers/symbol_table_compiler.rb +1 -1
- data/lib/tapioca/compilers/todos_compiler.rb +1 -1
- data/lib/tapioca/core_ext/class.rb +8 -3
- data/lib/tapioca/gemfile.rb +1 -1
- data/lib/tapioca/generator.rb +1 -1
- data/lib/tapioca/loader.rb +1 -1
- data/lib/tapioca/version.rb +1 -1
- metadata +17 -4
- data/lib/tapioca/sorbet_config_parser.rb +0 -77
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f225f517eb2bb6e6d7aa6910bb42a35280b57ad8223dbd8bc255ce92377c6eb3
         | 
| 4 | 
            +
              data.tar.gz: f3672f181cbcd71b9c8056c815e77313d75fcb2a78d2be5dbad3d2e51e35de39
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: dcd0b9ebf36c2a467bb2e88cb91b1f0634cb772a3a5cf29f7dd3b716ddc3c4fd2ea4dd84b671df243255cc15651deb157d149578dde07f3f7eb26f0a8814a297
         | 
| 7 | 
            +
              data.tar.gz: df7355fe19f05210797993286ead0f653a0f5b5f89263f469e8afece16d39026bde0cec1a0b266256ab236f43c27e95bd2912be3a9be74877ca6ca28037e09d7
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -11,6 +11,7 @@ group(:deployment, :development) do | |
| 11 11 | 
             
            end
         | 
| 12 12 |  | 
| 13 13 | 
             
            gem("bundler", "~> 1.17")
         | 
| 14 | 
            +
            gem("yard", "~> 0.9.25")
         | 
| 14 15 | 
             
            gem("pry-byebug")
         | 
| 15 16 | 
             
            gem("minitest")
         | 
| 16 17 | 
             
            gem("minitest-hooks")
         | 
| @@ -33,3 +34,5 @@ group(:development, :test) do | |
| 33 34 | 
             
              gem("activeresource", "~> 5.1", require: false)
         | 
| 34 35 | 
             
              gem("google-protobuf", "~>3.12.0", require: false)
         | 
| 35 36 | 
             
            end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            gem "rubocop-sorbet", ">= 0.4.1"
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # Tapioca
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            
         | 
| 4 4 |  | 
| 5 5 | 
             
            Tapioca is a library used to generate RBI (Ruby interface) files for use with [Sorbet](https://sorbet.org). RBI files provide the structure (classes, modules, methods, parameters) of the gem/library to Sorbet to assist with typechecking.
         | 
| 6 6 |  | 
| @@ -97,6 +97,12 @@ Command: `tapioca todo` | |
| 97 97 |  | 
| 98 98 | 
             
            This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved constants as empty modules.
         | 
| 99 99 |  | 
| 100 | 
            +
            ### Generate DSL RBI files
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            Command: `tapioca dsl [constant...]`
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            This will generate DSL RBIs for specified constants (or for all handled constants, if a constant name is not supplied). You can read about DSL RBI generators supplied by `tapioca` in [the manual](manual/generators.md).
         | 
| 105 | 
            +
             | 
| 100 106 | 
             
            ### Flags
         | 
| 101 107 |  | 
| 102 108 | 
             
            - `--prerequire [file]`: A file to be required before `Bundler.require` is called.
         | 
| @@ -105,10 +111,6 @@ This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved consta | |
| 105 111 | 
             
            - `--generate-command [command]`: The command to run to regenerate RBI files (used in header comment of the RBI files), defaults to the current command.
         | 
| 106 112 | 
             
            - `--typed-overrides [gem:level]`: Overrides typed sigils for generated gem RBIs for gem `gem` to level `level` (`level` can be one of `ignore`, `false`, `true`, `strict`, or `strong`, see [the Sorbet docs](https://sorbet.org/docs/static#file-level-granularity-strictness-levels) for more details).
         | 
| 107 113 |  | 
| 108 | 
            -
            ### Strong typing option for ActiveRecord column methods
         | 
| 109 | 
            -
             | 
| 110 | 
            -
            `tapioca` gives you the option to generate stricter type signatures for your ActiveRecord column types. By default, methods generated for columns that are defined in the schema have signatures of T.untyped. However, if the object extends a module with name StrongTypeGeneration, tapioca will generate stricter signatures that follow closely with the types defined in the schema. Expectation is the StrongTypeGeneration module you define in your application won't allow objects to be initialized with "bad state". It will check all the attributes that are not nillable to ensure they are not nil.
         | 
| 111 | 
            -
             | 
| 112 114 | 
             
            ## Contributing
         | 
| 113 115 |  | 
| 114 116 | 
             
            Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tapioca. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://github.com/Shopify/tapioca/blob/master/CODE_OF_CONDUCT.md) code of conduct.
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/lib/tapioca/cli.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 1 | 
             
            # typed: true
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require 'thor'
         | 
| 5 5 |  | 
| @@ -34,6 +34,8 @@ module Tapioca | |
| 34 34 | 
             
                              banner: "gem:level [gem:level ...]",
         | 
| 35 35 | 
             
                              desc: "Overrides for typed sigils for generated gem RBIs"
         | 
| 36 36 |  | 
| 37 | 
            +
                map T.unsafe(%w[--version -v] => :__print_version)
         | 
| 38 | 
            +
             | 
| 37 39 | 
             
                desc "init", "initializes folder structure"
         | 
| 38 40 | 
             
                def init
         | 
| 39 41 | 
             
                  create_file(Config::SORBET_CONFIG, skip: true) do
         | 
| @@ -44,8 +46,8 @@ module Tapioca | |
| 44 46 | 
             
                  end
         | 
| 45 47 | 
             
                  create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do
         | 
| 46 48 | 
             
                    <<~CONTENT
         | 
| 47 | 
            -
                      # frozen_string_literal: true
         | 
| 48 49 | 
             
                      # typed: false
         | 
| 50 | 
            +
                      # frozen_string_literal: true
         | 
| 49 51 |  | 
| 50 52 | 
             
                      # Add your extra requires here
         | 
| 51 53 | 
             
                    CONTENT
         | 
| @@ -92,6 +94,11 @@ module Tapioca | |
| 92 94 | 
             
                  end
         | 
| 93 95 | 
             
                end
         | 
| 94 96 |  | 
| 97 | 
            +
                desc "--version, -v", "show version"
         | 
| 98 | 
            +
                def __print_version
         | 
| 99 | 
            +
                  puts "Tapioca v#{Tapioca::VERSION}"
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 95 102 | 
             
                no_commands do
         | 
| 96 103 | 
             
                  def self.exit_on_failure?
         | 
| 97 104 | 
             
                    true
         | 
| @@ -45,10 +45,10 @@ module Tapioca | |
| 45 45 | 
             
                  #   sig { params(value: T.nilable(::User)).void }
         | 
| 46 46 | 
             
                  #   def author=(value); end
         | 
| 47 47 | 
             
                  #
         | 
| 48 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 48 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::User) }
         | 
| 49 49 | 
             
                  #   def build_author(*args, &blk); end
         | 
| 50 50 | 
             
                  #
         | 
| 51 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 51 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::Category) }
         | 
| 52 52 | 
             
                  #   def build_category(*args, &blk); end
         | 
| 53 53 | 
             
                  #
         | 
| 54 54 | 
             
                  #   sig { returns(T.nilable(::Category)) }
         | 
| @@ -69,16 +69,16 @@ module Tapioca | |
| 69 69 | 
             
                  #   sig { params(value: T::Enumerable[::Comment]).void }
         | 
| 70 70 | 
             
                  #   def comments=(value); end
         | 
| 71 71 | 
             
                  #
         | 
| 72 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 72 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::User) }
         | 
| 73 73 | 
             
                  #   def create_author(*args, &blk); end
         | 
| 74 74 | 
             
                  #
         | 
| 75 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 75 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::User) }
         | 
| 76 76 | 
             
                  #   def create_author!(*args, &blk); end
         | 
| 77 77 | 
             
                  #
         | 
| 78 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 78 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::Category) }
         | 
| 79 79 | 
             
                  #   def create_category(*args, &blk); end
         | 
| 80 80 | 
             
                  #
         | 
| 81 | 
            -
                  #   sig { params(args: T.untyped, blk: T.untyped).returns( | 
| 81 | 
            +
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(::Category) }
         | 
| 82 82 | 
             
                  #   def create_category!(*args, &blk); end
         | 
| 83 83 | 
             
                  #
         | 
| 84 84 | 
             
                  #   sig { returns(T.nilable(::User)) }
         | 
| @@ -132,11 +132,7 @@ module Tapioca | |
| 132 132 | 
             
                    end
         | 
| 133 133 | 
             
                    def populate_single_assoc_getter_setter(klass, constant, association_name, reflection)
         | 
| 134 134 | 
             
                      association_class = type_for(constant, reflection)
         | 
| 135 | 
            -
                      association_type =  | 
| 136 | 
            -
                        association_class
         | 
| 137 | 
            -
                      else
         | 
| 138 | 
            -
                        "T.nilable(#{association_class})"
         | 
| 139 | 
            -
                      end
         | 
| 135 | 
            +
                      association_type = "T.nilable(#{association_class})"
         | 
| 140 136 |  | 
| 141 137 | 
             
                      create_method(
         | 
| 142 138 | 
             
                        klass,
         | 
| @@ -164,7 +160,7 @@ module Tapioca | |
| 164 160 | 
             
                            Parlour::RbiGenerator::Parameter.new("*args", type: "T.untyped"),
         | 
| 165 161 | 
             
                            Parlour::RbiGenerator::Parameter.new("&blk", type: "T.untyped"),
         | 
| 166 162 | 
             
                          ],
         | 
| 167 | 
            -
                          return_type:  | 
| 163 | 
            +
                          return_type: association_class
         | 
| 168 164 | 
             
                        )
         | 
| 169 165 | 
             
                        create_method(
         | 
| 170 166 | 
             
                          klass,
         | 
| @@ -173,7 +169,7 @@ module Tapioca | |
| 173 169 | 
             
                            Parlour::RbiGenerator::Parameter.new("*args", type: "T.untyped"),
         | 
| 174 170 | 
             
                            Parlour::RbiGenerator::Parameter.new("&blk", type: "T.untyped"),
         | 
| 175 171 | 
             
                          ],
         | 
| 176 | 
            -
                          return_type:  | 
| 172 | 
            +
                          return_type: association_class
         | 
| 177 173 | 
             
                        )
         | 
| 178 174 | 
             
                        create_method(
         | 
| 179 175 | 
             
                          klass,
         | 
| @@ -182,7 +178,7 @@ module Tapioca | |
| 182 178 | 
             
                            Parlour::RbiGenerator::Parameter.new("*args", type: "T.untyped"),
         | 
| 183 179 | 
             
                            Parlour::RbiGenerator::Parameter.new("&blk", type: "T.untyped"),
         | 
| 184 180 | 
             
                          ],
         | 
| 185 | 
            -
                          return_type:  | 
| 181 | 
            +
                          return_type: association_class
         | 
| 186 182 | 
             
                        )
         | 
| 187 183 | 
             
                      end
         | 
| 188 184 | 
             
                    end
         | 
| @@ -227,20 +223,6 @@ module Tapioca | |
| 227 223 | 
             
                      )
         | 
| 228 224 | 
             
                    end
         | 
| 229 225 |  | 
| 230 | 
            -
                    sig do
         | 
| 231 | 
            -
                      params(
         | 
| 232 | 
            -
                        constant: T.class_of(ActiveRecord::Base),
         | 
| 233 | 
            -
                        reflection: ReflectionType
         | 
| 234 | 
            -
                      ).returns(T::Boolean)
         | 
| 235 | 
            -
                    end
         | 
| 236 | 
            -
                    def belongs_to_and_required?(constant, reflection)
         | 
| 237 | 
            -
                      return false unless constant.table_exists?
         | 
| 238 | 
            -
                      return false unless reflection.belongs_to?
         | 
| 239 | 
            -
                      column_definition = constant.columns_hash[reflection.foreign_key.to_s]
         | 
| 240 | 
            -
             | 
| 241 | 
            -
                      !column_definition.nil? && !column_definition.null
         | 
| 242 | 
            -
                    end
         | 
| 243 | 
            -
             | 
| 244 226 | 
             
                    sig do
         | 
| 245 227 | 
             
                      params(
         | 
| 246 228 | 
             
                        constant: T.class_of(ActiveRecord::Base),
         | 
| @@ -17,6 +17,17 @@ module Tapioca | |
| 17 17 | 
             
                  # responsible for defining the attribute methods that would be created for the columns that
         | 
| 18 18 | 
             
                  # are defined in the Active Record model.
         | 
| 19 19 | 
             
                  #
         | 
| 20 | 
            +
                  # **Note:** This generator, by default, generates weak signatures for column methods and treats each
         | 
| 21 | 
            +
                  # column to be `T.untyped`. This is done on purpose to ensure that the nilability of Active Record
         | 
| 22 | 
            +
                  # columns do not make it hard for existing code to adopt gradual typing. It is possible, however, to
         | 
| 23 | 
            +
                  # generate stricter type signatures for your ActiveRecord column types. If your ActiveRecord model extends
         | 
| 24 | 
            +
                  # a module with name `StrongTypeGeneration`, this generator will generate stricter signatures that follow
         | 
| 25 | 
            +
                  # closely with the types defined in the schema.
         | 
| 26 | 
            +
                  #
         | 
| 27 | 
            +
                  # The `StrongTypeGeneration` module you define in your application should add an `after_initialize` callback
         | 
| 28 | 
            +
                  # to the model and ensure that all the non-nilable attributes of the model are actually initialized with non-`nil`
         | 
| 29 | 
            +
                  # values.
         | 
| 30 | 
            +
                  #
         | 
| 20 31 | 
             
                  # For example, with the following model class:
         | 
| 21 32 | 
             
                  #
         | 
| 22 33 | 
             
                  # ~~~rb
         | 
| @@ -196,25 +207,25 @@ module Tapioca | |
| 196 207 | 
             
                        klass,
         | 
| 197 208 | 
             
                        "#{attribute_name}_before_last_save",
         | 
| 198 209 | 
             
                        methods_to_add,
         | 
| 199 | 
            -
                        return_type: getter_type
         | 
| 210 | 
            +
                        return_type: as_nilable_type(getter_type)
         | 
| 200 211 | 
             
                      )
         | 
| 201 212 | 
             
                      add_method(
         | 
| 202 213 | 
             
                        klass,
         | 
| 203 214 | 
             
                        "#{attribute_name}_change_to_be_saved",
         | 
| 204 215 | 
             
                        methods_to_add,
         | 
| 205 | 
            -
                        return_type: "[#{getter_type}, #{getter_type}]"
         | 
| 216 | 
            +
                        return_type: "T.nilable([#{getter_type}, #{getter_type}])"
         | 
| 206 217 | 
             
                      )
         | 
| 207 218 | 
             
                      add_method(
         | 
| 208 219 | 
             
                        klass,
         | 
| 209 220 | 
             
                        "#{attribute_name}_in_database",
         | 
| 210 221 | 
             
                        methods_to_add,
         | 
| 211 | 
            -
                        return_type: getter_type
         | 
| 222 | 
            +
                        return_type: as_nilable_type(getter_type)
         | 
| 212 223 | 
             
                      )
         | 
| 213 224 | 
             
                      add_method(
         | 
| 214 225 | 
             
                        klass,
         | 
| 215 226 | 
             
                        "saved_change_to_#{attribute_name}",
         | 
| 216 227 | 
             
                        methods_to_add,
         | 
| 217 | 
            -
                        return_type: "[#{getter_type}, #{getter_type}]"
         | 
| 228 | 
            +
                        return_type: "T.nilable([#{getter_type}, #{getter_type}])"
         | 
| 218 229 | 
             
                      )
         | 
| 219 230 | 
             
                      add_method(
         | 
| 220 231 | 
             
                        klass,
         | 
| @@ -235,7 +246,7 @@ module Tapioca | |
| 235 246 | 
             
                        klass,
         | 
| 236 247 | 
             
                        "#{attribute_name}_change",
         | 
| 237 248 | 
             
                        methods_to_add,
         | 
| 238 | 
            -
                        return_type: "[#{getter_type}, #{getter_type}]"
         | 
| 249 | 
            +
                        return_type: "T.nilable([#{getter_type}, #{getter_type}])"
         | 
| 239 250 | 
             
                      )
         | 
| 240 251 | 
             
                      add_method(
         | 
| 241 252 | 
             
                        klass,
         | 
| @@ -252,13 +263,13 @@ module Tapioca | |
| 252 263 | 
             
                        klass,
         | 
| 253 264 | 
             
                        "#{attribute_name}_was",
         | 
| 254 265 | 
             
                        methods_to_add,
         | 
| 255 | 
            -
                        return_type: getter_type
         | 
| 266 | 
            +
                        return_type: as_nilable_type(getter_type)
         | 
| 256 267 | 
             
                      )
         | 
| 257 268 | 
             
                      add_method(
         | 
| 258 269 | 
             
                        klass,
         | 
| 259 270 | 
             
                        "#{attribute_name}_previous_change",
         | 
| 260 271 | 
             
                        methods_to_add,
         | 
| 261 | 
            -
                        return_type: "[#{getter_type}, #{getter_type}]"
         | 
| 272 | 
            +
                        return_type: "T.nilable([#{getter_type}, #{getter_type}])"
         | 
| 262 273 | 
             
                      )
         | 
| 263 274 | 
             
                      add_method(
         | 
| 264 275 | 
             
                        klass,
         | 
| @@ -270,7 +281,7 @@ module Tapioca | |
| 270 281 | 
             
                        klass,
         | 
| 271 282 | 
             
                        "#{attribute_name}_previously_was",
         | 
| 272 283 | 
             
                        methods_to_add,
         | 
| 273 | 
            -
                        return_type: getter_type
         | 
| 284 | 
            +
                        return_type: as_nilable_type(getter_type)
         | 
| 274 285 | 
             
                      )
         | 
| 275 286 | 
             
                      add_method(
         | 
| 276 287 | 
             
                        klass,
         | 
| @@ -381,6 +392,12 @@ module Tapioca | |
| 381 392 |  | 
| 382 393 | 
             
                      arg_type.to_s
         | 
| 383 394 | 
             
                    end
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                    sig { params(type: String).returns(String) }
         | 
| 397 | 
            +
                    def as_nilable_type(type)
         | 
| 398 | 
            +
                      return type if type.start_with?("T.nilable(")
         | 
| 399 | 
            +
                      "T.nilable(#{type})"
         | 
| 400 | 
            +
                    end
         | 
| 384 401 | 
             
                  end
         | 
| 385 402 | 
             
                end
         | 
| 386 403 | 
             
              end
         | 
| @@ -16,7 +16,7 @@ module Tapioca | |
| 16 16 | 
             
              module Compilers
         | 
| 17 17 | 
             
                module Dsl
         | 
| 18 18 | 
             
                  # `Tapioca::Compilers::DSL::ActiveRecordIdentityCache` generates RBI files for ActiveRecord models
         | 
| 19 | 
            -
                  #  that use `include IdentityCache | 
| 19 | 
            +
                  #  that use `include IdentityCache`.
         | 
| 20 20 | 
             
                  # `IdentityCache` is a blob level caching solution to plug into ActiveRecord. (see https://github.com/Shopify/identity_cache).
         | 
| 21 21 | 
             
                  #
         | 
| 22 22 | 
             
                  # For example, with the following ActiveRecord class:
         | 
| @@ -61,7 +61,6 @@ module Tapioca | |
| 61 61 | 
             
                  #   def fetch_by_title_and_review_date(title, review_date, includes: nil); end
         | 
| 62 62 | 
             
                  # end
         | 
| 63 63 | 
             
                  # ~~~
         | 
| 64 | 
            -
             | 
| 65 64 | 
             
                  class ActiveRecordIdentityCache < Base
         | 
| 66 65 | 
             
                    extend T::Sig
         | 
| 67 66 |  | 
| @@ -109,7 +108,7 @@ module Tapioca | |
| 109 108 | 
             
                    sig { override.returns(T::Enumerable[Module]) }
         | 
| 110 109 | 
             
                    def gather_constants
         | 
| 111 110 | 
             
                      ::ActiveRecord::Base.descendants.select do |klass|
         | 
| 112 | 
            -
                        klass < IdentityCache
         | 
| 111 | 
            +
                        klass < IdentityCache::WithoutPrimaryIndex
         | 
| 113 112 | 
             
                      end
         | 
| 114 113 | 
             
                    end
         | 
| 115 114 |  | 
| @@ -127,7 +126,7 @@ module Tapioca | |
| 127 126 | 
             
                      if returns_collection
         | 
| 128 127 | 
             
                        COLLECTION_TYPE.call(cache_type)
         | 
| 129 128 | 
             
                      else
         | 
| 130 | 
            -
                        "::#{cache_type}"
         | 
| 129 | 
            +
                        "T.nilable(::#{cache_type})"
         | 
| 131 130 | 
             
                      end
         | 
| 132 131 | 
             
                    rescue ArgumentError
         | 
| 133 132 | 
             
                      "T.untyped"
         | 
| @@ -37,7 +37,7 @@ module Tapioca | |
| 37 37 | 
             
                  # module Post::GeneratedRelationMethods
         | 
| 38 38 | 
             
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
         | 
| 39 39 | 
             
                  #   def private_kind(*args, &blk); end
         | 
| 40 | 
            -
             | 
| 40 | 
            +
                  #
         | 
| 41 41 | 
             
                  #   sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
         | 
| 42 42 | 
             
                  #   def public_kind(*args, &blk); end
         | 
| 43 43 | 
             
                  # end
         | 
| @@ -92,24 +92,28 @@ module Tapioca | |
| 92 92 | 
             
                      method_def = signature.nil? ? method_def : signature.method
         | 
| 93 93 | 
             
                      method_types = parameters_types_from_signature(method_def, signature)
         | 
| 94 94 |  | 
| 95 | 
            -
                      method_def.parameters.each_with_index.map do |(type, name),  | 
| 96 | 
            -
                         | 
| 97 | 
            -
             | 
| 95 | 
            +
                      method_def.parameters.each_with_index.map do |(type, name), index|
         | 
| 96 | 
            +
                        fallback_arg_name = "_arg#{index}"
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                        name ||= fallback_arg_name
         | 
| 99 | 
            +
                        name = name.to_s.gsub(/&|\*/, fallback_arg_name) # avoid incorrect names from `delegate`
         | 
| 100 | 
            +
                        method_type = method_types[index]
         | 
| 101 | 
            +
             | 
| 98 102 | 
             
                        case type
         | 
| 99 103 | 
             
                        when :req
         | 
| 100 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new(name, type:  | 
| 104 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new(name, type: method_type)
         | 
| 101 105 | 
             
                        when :opt
         | 
| 102 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new(name, type:  | 
| 106 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new(name, type: method_type, default: 'T.unsafe(nil)')
         | 
| 103 107 | 
             
                        when :rest
         | 
| 104 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new("*#{name}", type:  | 
| 108 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new("*#{name}", type: method_type)
         | 
| 105 109 | 
             
                        when :keyreq
         | 
| 106 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new("#{name}:", type:  | 
| 110 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new("#{name}:", type: method_type)
         | 
| 107 111 | 
             
                        when :key
         | 
| 108 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new("#{name}:", type:  | 
| 112 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new("#{name}:", type: method_type, default: 'T.unsafe(nil)')
         | 
| 109 113 | 
             
                        when :keyrest
         | 
| 110 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new("**#{name}", type:  | 
| 114 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new("**#{name}", type: method_type)
         | 
| 111 115 | 
             
                        when :block
         | 
| 112 | 
            -
                          ::Parlour::RbiGenerator::Parameter.new("&#{name}", type:  | 
| 116 | 
            +
                          ::Parlour::RbiGenerator::Parameter.new("&#{name}", type: method_type)
         | 
| 113 117 | 
             
                        else
         | 
| 114 118 | 
             
                          raise "Unknown type `#{type}`."
         | 
| 115 119 | 
             
                        end
         | 
| @@ -12,19 +12,19 @@ module Tapioca | |
| 12 12 | 
             
              module Compilers
         | 
| 13 13 | 
             
                module Dsl
         | 
| 14 14 | 
             
                  # `Tapioca::Compilers::Dsl::Protobuf` decorates RBI files for subclasses of
         | 
| 15 | 
            -
                  # `Google::Protobuf::MessageExts | 
| 16 | 
            -
                  # (see https://github.com/coinbase/protoc-gen-rbi).
         | 
| 15 | 
            +
                  # `Google::Protobuf::MessageExts` (see https://github.com/protocolbuffers/protobuf/tree/master/ruby).
         | 
| 17 16 | 
             
                  #
         | 
| 18 17 | 
             
                  # For example, with the following "cart.rb" file:
         | 
| 19 18 | 
             
                  #
         | 
| 20 19 | 
             
                  # ~~~rb
         | 
| 21 20 | 
             
                  # Google::Protobuf::DescriptorPool.generated_pool.build do
         | 
| 22 | 
            -
                  # | 
| 23 | 
            -
                  # | 
| 24 | 
            -
                  # | 
| 25 | 
            -
                  # | 
| 26 | 
            -
                  # | 
| 27 | 
            -
                  # | 
| 21 | 
            +
                  #   add_file("cart.proto", :syntax => :proto3) do
         | 
| 22 | 
            +
                  #     add_message "MyCart" do
         | 
| 23 | 
            +
                  #       optional :shop_id, :int32, 1
         | 
| 24 | 
            +
                  #       optional :customer_id, :int64, 2
         | 
| 25 | 
            +
                  #       optional :number_value, :double, 3
         | 
| 26 | 
            +
                  #       optional :string_value, :string, 4
         | 
| 27 | 
            +
                  #     end
         | 
| 28 28 | 
             
                  #   end
         | 
| 29 29 | 
             
                  # end
         | 
| 30 30 | 
             
                  # ~~~
         | 
| @@ -14,6 +14,74 @@ end | |
| 14 14 | 
             
            module Tapioca
         | 
| 15 15 | 
             
              module Compilers
         | 
| 16 16 | 
             
                module Dsl
         | 
| 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).
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # For example, with the following setup:
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  # ~~~rb
         | 
| 24 | 
            +
                  # # config/application.rb
         | 
| 25 | 
            +
                  # class Application < Rails::Application
         | 
| 26 | 
            +
                  #   routes.draw do
         | 
| 27 | 
            +
                  #     resource :index
         | 
| 28 | 
            +
                  #   end
         | 
| 29 | 
            +
                  # end
         | 
| 30 | 
            +
                  # ~~~
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # ~~~rb
         | 
| 33 | 
            +
                  # app/models/post.rb
         | 
| 34 | 
            +
                  # class Post
         | 
| 35 | 
            +
                  #   include Rails.application.routes.url_helpers
         | 
| 36 | 
            +
                  # end
         | 
| 37 | 
            +
                  # ~~~
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # this generator will produce the following RBI files:
         | 
| 40 | 
            +
                  #
         | 
| 41 | 
            +
                  # ~~~rbi
         | 
| 42 | 
            +
                  # # generated_path_helpers_module.rbi
         | 
| 43 | 
            +
                  # # typed: true
         | 
| 44 | 
            +
                  # module GeneratedPathHelpersModule
         | 
| 45 | 
            +
                  #   include ActionDispatch::Routing::PolymorphicRoutes
         | 
| 46 | 
            +
                  #   include ActionDispatch::Routing::UrlFor
         | 
| 47 | 
            +
                  #
         | 
| 48 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 49 | 
            +
                  #   def edit_index_path(*args); end
         | 
| 50 | 
            +
                  #
         | 
| 51 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 52 | 
            +
                  #   def index_path(*args); end
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 55 | 
            +
                  #   def new_index_path(*args); end
         | 
| 56 | 
            +
                  # end
         | 
| 57 | 
            +
                  # ~~~
         | 
| 58 | 
            +
                  #
         | 
| 59 | 
            +
                  # ~~~rbi
         | 
| 60 | 
            +
                  # # generated_url_helpers_module.rbi
         | 
| 61 | 
            +
                  # # typed: true
         | 
| 62 | 
            +
                  # module GeneratedUrlHelpersModule
         | 
| 63 | 
            +
                  #   include ActionDispatch::Routing::PolymorphicRoutes
         | 
| 64 | 
            +
                  #   include ActionDispatch::Routing::UrlFor
         | 
| 65 | 
            +
                  #
         | 
| 66 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 67 | 
            +
                  #   def edit_index_url(*args); end
         | 
| 68 | 
            +
                  #
         | 
| 69 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 70 | 
            +
                  #   def index_url(*args); end
         | 
| 71 | 
            +
                  #
         | 
| 72 | 
            +
                  #   sig { params(args: T.untyped).returns(String) }
         | 
| 73 | 
            +
                  #   def new_index_url(*args); end
         | 
| 74 | 
            +
                  # end
         | 
| 75 | 
            +
                  # ~~~
         | 
| 76 | 
            +
                  #
         | 
| 77 | 
            +
                  # ~~~rbi
         | 
| 78 | 
            +
                  # # post.rbi
         | 
| 79 | 
            +
                  # # typed: true
         | 
| 80 | 
            +
                  # class Post
         | 
| 81 | 
            +
                  #   include GeneratedPathHelpersModule
         | 
| 82 | 
            +
                  #   include GeneratedUrlHelpersModule
         | 
| 83 | 
            +
                  # end
         | 
| 84 | 
            +
                  # ~~~
         | 
| 17 85 | 
             
                  class UrlHelpers < Base
         | 
| 18 86 | 
             
                    extend T::Sig
         | 
| 19 87 |  | 
| @@ -1,5 +1,5 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 1 2 | 
             
            # frozen_string_literal: true
         | 
| 2 | 
            -
            # typed: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "tapioca/compilers/dsl/base"
         | 
| 5 5 |  | 
| @@ -30,7 +30,7 @@ module Tapioca | |
| 30 30 | 
             
                      T::Enumerable[Dsl::Base]
         | 
| 31 31 | 
             
                    )
         | 
| 32 32 | 
             
                    @requested_constants = requested_constants
         | 
| 33 | 
            -
                    @error_handler = error_handler || $stderr.method(:puts)
         | 
| 33 | 
            +
                    @error_handler = T.let(error_handler || $stderr.method(:puts), T.proc.params(error: String).void)
         | 
| 34 34 | 
             
                  end
         | 
| 35 35 |  | 
| 36 36 | 
             
                  sig { params(blk: T.proc.params(constant: Module, rbi: String).void).void }
         | 
| @@ -54,9 +54,9 @@ module Tapioca | |
| 54 54 |  | 
| 55 55 | 
             
                  private
         | 
| 56 56 |  | 
| 57 | 
            -
                  sig { params(requested_generators: T::Array[String]).returns( | 
| 57 | 
            +
                  sig { params(requested_generators: T::Array[String]).returns(T.proc.params(klass: Class).returns(T::Boolean)) }
         | 
| 58 58 | 
             
                  def generator_filter(requested_generators)
         | 
| 59 | 
            -
                    return  | 
| 59 | 
            +
                    return ->(_klass) { true } if requested_generators.empty?
         | 
| 60 60 |  | 
| 61 61 | 
             
                    generators = requested_generators.map(&:downcase)
         | 
| 62 62 |  | 
| @@ -70,7 +70,7 @@ module Tapioca | |
| 70 70 | 
             
                  def gather_generators(requested_generators)
         | 
| 71 71 | 
             
                    generator_filter = generator_filter(requested_generators)
         | 
| 72 72 |  | 
| 73 | 
            -
                    Dsl::Base.descendants.select(&generator_filter).map(&:new)
         | 
| 73 | 
            +
                    T.cast(Dsl::Base.descendants.select(&generator_filter).map(&:new), T::Enumerable[Dsl::Base])
         | 
| 74 74 | 
             
                  end
         | 
| 75 75 |  | 
| 76 76 | 
             
                  sig { params(requested_constants: T::Array[Module]).returns(T::Set[Module]) }
         | 
| @@ -1,7 +1,7 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 1 | 
             
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            -
             | 
| 4 | 
            +
            require 'spoom'
         | 
| 5 5 |  | 
| 6 6 | 
             
            module Tapioca
         | 
| 7 7 | 
             
              module Compilers
         | 
| @@ -15,7 +15,7 @@ module Tapioca | |
| 15 15 |  | 
| 16 16 | 
             
                  sig { returns(String) }
         | 
| 17 17 | 
             
                  def compile
         | 
| 18 | 
            -
                    config =  | 
| 18 | 
            +
                    config = Spoom::Sorbet::Config.parse_file(@sorbet_path)
         | 
| 19 19 | 
             
                    files = collect_files(config)
         | 
| 20 20 | 
             
                    files.flat_map do |file|
         | 
| 21 21 | 
             
                      collect_requires(file).reject do |req|
         | 
| @@ -28,13 +28,14 @@ module Tapioca | |
| 28 28 |  | 
| 29 29 | 
             
                  private
         | 
| 30 30 |  | 
| 31 | 
            -
                  sig { params(config:  | 
| 31 | 
            +
                  sig { params(config: Spoom::Sorbet::Config).returns(T::Array[String]) }
         | 
| 32 32 | 
             
                  def collect_files(config)
         | 
| 33 33 | 
             
                    config.paths.flat_map do |path|
         | 
| 34 34 | 
             
                      path = (Pathname.new(@sorbet_path) / "../.." / path).cleanpath
         | 
| 35 35 | 
             
                      if path.directory?
         | 
| 36 36 | 
             
                        Dir.glob("#{path}/**/*.rb", File::FNM_EXTGLOB).reject do |file|
         | 
| 37 | 
            -
                           | 
| 37 | 
            +
                          relative_file_path = Pathname.new(file).relative_path_from(path)
         | 
| 38 | 
            +
                          file_ignored_by_sorbet?(config, relative_file_path)
         | 
| 38 39 | 
             
                        end
         | 
| 39 40 | 
             
                      else
         | 
| 40 41 | 
             
                        [path.to_s]
         | 
| @@ -49,13 +50,40 @@ module Tapioca | |
| 49 50 | 
             
                    end.compact
         | 
| 50 51 | 
             
                  end
         | 
| 51 52 |  | 
| 52 | 
            -
                  sig { params(config:  | 
| 53 | 
            -
                  def file_ignored_by_sorbet?(config,  | 
| 54 | 
            -
                     | 
| 55 | 
            -
             | 
| 53 | 
            +
                  sig { params(config: Spoom::Sorbet::Config, file_path: Pathname).returns(T::Boolean) }
         | 
| 54 | 
            +
                  def file_ignored_by_sorbet?(config, file_path)
         | 
| 55 | 
            +
                    file_path_parts = path_parts(file_path)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    config.ignore.any? do |ignore|
         | 
| 58 | 
            +
                      # Sorbet --ignore matching method:
         | 
| 59 | 
            +
                      # ---
         | 
| 60 | 
            +
                      # Ignores input files that contain the given
         | 
| 61 | 
            +
                      # string in their paths (relative to the input
         | 
| 62 | 
            +
                      # path passed to Sorbet).
         | 
| 63 | 
            +
                      #
         | 
| 64 | 
            +
                      # Strings beginning with / match against the
         | 
| 65 | 
            +
                      # prefix of these relative paths; others are
         | 
| 66 | 
            +
                      # substring matchs.
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                      # Matches must be against whole folder and file
         | 
| 69 | 
            +
                      # names, so `foo` matches `/foo/bar.rb` and
         | 
| 70 | 
            +
                      # `/bar/foo/baz.rb` but not `/foo.rb` or
         | 
| 71 | 
            +
                      # `/foo2/bar.rb`.
         | 
| 72 | 
            +
                      ignore_parts = path_parts(Pathname.new(ignore))
         | 
| 73 | 
            +
                      file_path_part_sequences = file_path_parts.each_cons(ignore_parts.size)
         | 
| 74 | 
            +
                      # if ignore string begins with /, we only want the first sequence to match
         | 
| 75 | 
            +
                      file_path_part_sequences = [file_path_part_sequences.first].to_enum if ignore.start_with?("/")
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      # we need to match whole segments
         | 
| 78 | 
            +
                      file_path_part_sequences.include?(ignore_parts)
         | 
| 56 79 | 
             
                    end
         | 
| 57 80 | 
             
                  end
         | 
| 58 81 |  | 
| 82 | 
            +
                  sig { params(path: Pathname).returns(T::Array[String]) }
         | 
| 83 | 
            +
                  def path_parts(path)
         | 
| 84 | 
            +
                    T.unsafe(path).descend.map { |part| part.basename.to_s }
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 59 87 | 
             
                  sig { params(files: T::Enumerable[String], name: String).returns(T::Boolean) }
         | 
| 60 88 | 
             
                  def name_in_project?(files, name)
         | 
| 61 89 | 
             
                    files.any? do |file|
         | 
| @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 1 | 
             
            # typed: true
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require 'pathname'
         | 
| 5 5 |  | 
| @@ -209,7 +209,11 @@ module Tapioca | |
| 209 209 | 
             
                        method = "const" if prop.fetch(:immutable, false)
         | 
| 210 210 | 
             
                        type = prop.fetch(:type_object, "T.untyped")
         | 
| 211 211 |  | 
| 212 | 
            -
                         | 
| 212 | 
            +
                        if prop.key?(:default)
         | 
| 213 | 
            +
                          indented("#{method} :#{name}, #{type}, default: T.unsafe(nil)")
         | 
| 214 | 
            +
                        else
         | 
| 215 | 
            +
                          indented("#{method} :#{name}, #{type}")
         | 
| 216 | 
            +
                        end
         | 
| 213 217 | 
             
                      end.join("\n")
         | 
| 214 218 | 
             
                    end
         | 
| 215 219 |  | 
| @@ -383,8 +387,18 @@ module Tapioca | |
| 383 387 | 
             
                          indented("include(#{qualified_name_of(mod)})")
         | 
| 384 388 | 
             
                        end.join("\n")
         | 
| 385 389 |  | 
| 386 | 
            -
                       | 
| 387 | 
            -
             | 
| 390 | 
            +
                      ancestors = singleton_class_of(constant).ancestors
         | 
| 391 | 
            +
                      extends_as_concern = ancestors.any? do |mod|
         | 
| 392 | 
            +
                        qualified_name_of(mod) == "::ActiveSupport::Concern"
         | 
| 393 | 
            +
                      end
         | 
| 394 | 
            +
                      class_methods_module = resolve_constant("#{name_of(constant)}::ClassMethods")
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                      mixed_in_module = if extends_as_concern && Module === class_methods_module
         | 
| 397 | 
            +
                        class_methods_module
         | 
| 398 | 
            +
                      else
         | 
| 399 | 
            +
                        dynamic_extends.find do |mod|
         | 
| 400 | 
            +
                          mod != constant && public_module?(mod)
         | 
| 401 | 
            +
                        end
         | 
| 388 402 | 
             
                      end
         | 
| 389 403 |  | 
| 390 404 | 
             
                      return result if mixed_in_module.nil?
         | 
| @@ -494,15 +508,18 @@ module Tapioca | |
| 494 508 | 
             
                      return if symbol_ignored?(symbol_name) && !method_in_gem?(method)
         | 
| 495 509 |  | 
| 496 510 | 
             
                      signature = signature_of(method)
         | 
| 497 | 
            -
                      method = signature.method if signature
         | 
| 511 | 
            +
                      method = T.let(signature.method, UnboundMethod) if signature
         | 
| 498 512 |  | 
| 499 513 | 
             
                      method_name = method.name.to_s
         | 
| 500 514 | 
             
                      return unless valid_method_name?(method_name)
         | 
| 501 515 | 
             
                      return if struct_method?(constant, method_name)
         | 
| 502 516 | 
             
                      return if method_name.start_with?("__t_props_generated_")
         | 
| 503 517 |  | 
| 504 | 
            -
                       | 
| 505 | 
            -
             | 
| 518 | 
            +
                      parameters = T.let(method.parameters, T::Array[[Symbol, T.nilable(Symbol)]])
         | 
| 519 | 
            +
             | 
| 520 | 
            +
                      sanitized_parameters = parameters.each_with_index.map do |(type, name), index|
         | 
| 521 | 
            +
                        fallback_arg_name = "_arg#{index}"
         | 
| 522 | 
            +
             | 
| 506 523 | 
             
                        unless name
         | 
| 507 524 | 
             
                          # For attr_writer methods, Sorbet signatures have the name
         | 
| 508 525 | 
             
                          # of the method (without the trailing = sign) as the name of
         | 
| @@ -512,22 +529,27 @@ module Tapioca | |
| 512 529 | 
             
                          # method and the parameter is required and there is a single
         | 
| 513 530 | 
             
                          # parameter and the signature also defines a single parameter and
         | 
| 514 531 | 
             
                          # the name of the method ends with a = character.
         | 
| 515 | 
            -
                          writer_method_with_sig =  | 
| 516 | 
            -
                            type == :req &&
         | 
| 517 | 
            -
                             | 
| 532 | 
            +
                          writer_method_with_sig = (
         | 
| 533 | 
            +
                            signature && type == :req &&
         | 
| 534 | 
            +
                            parameters.size == 1 &&
         | 
| 518 535 | 
             
                            signature.arg_types.size == 1 &&
         | 
| 519 536 | 
             
                            method_name[-1] == "="
         | 
| 537 | 
            +
                          )
         | 
| 520 538 |  | 
| 521 539 | 
             
                          name = if writer_method_with_sig
         | 
| 522 | 
            -
                            method_name[0...-1].to_sym
         | 
| 540 | 
            +
                            T.must(method_name[0...-1]).to_sym
         | 
| 523 541 | 
             
                          else
         | 
| 524 | 
            -
                             | 
| 542 | 
            +
                            fallback_arg_name
         | 
| 525 543 | 
             
                          end
         | 
| 526 544 | 
             
                        end
         | 
| 527 545 |  | 
| 528 546 | 
             
                        # Sanitize param names
         | 
| 529 | 
            -
                        name = name.to_s.gsub(/[^a-zA-Z0-9_]/,  | 
| 547 | 
            +
                        name = name.to_s.gsub(/[^a-zA-Z0-9_]/, fallback_arg_name)
         | 
| 548 | 
            +
             | 
| 549 | 
            +
                        [type, name]
         | 
| 550 | 
            +
                      end
         | 
| 530 551 |  | 
| 552 | 
            +
                      parameter_list = sanitized_parameters.map do |type, name|
         | 
| 531 553 | 
             
                        case type
         | 
| 532 554 | 
             
                        when :req
         | 
| 533 555 | 
             
                          name
         | 
| @@ -546,26 +568,31 @@ module Tapioca | |
| 546 568 | 
             
                        end
         | 
| 547 569 | 
             
                      end.join(', ')
         | 
| 548 570 |  | 
| 549 | 
            -
                       | 
| 571 | 
            +
                      parameter_list = "(#{parameter_list})" if parameter_list != ""
         | 
| 572 | 
            +
                      signature_str = indented(compile_signature(signature, sanitized_parameters)) if signature
         | 
| 550 573 |  | 
| 551 | 
            -
                      signature_str = indented(compile_signature(signature)) if signature
         | 
| 552 574 | 
             
                      [
         | 
| 553 575 | 
             
                        signature_str,
         | 
| 554 | 
            -
                        indented("def #{method_name}#{ | 
| 576 | 
            +
                        indented("def #{method_name}#{parameter_list}; end"),
         | 
| 555 577 | 
             
                      ].compact.join("\n")
         | 
| 556 578 | 
             
                    end
         | 
| 557 579 |  | 
| 558 580 | 
             
                    TYPE_PARAMETER_MATCHER = /T\.type_parameter\(:?([[:word:]]+)\)/
         | 
| 559 581 |  | 
| 560 | 
            -
                    sig { params(signature: T.untyped).returns(String) }
         | 
| 561 | 
            -
                    def compile_signature(signature)
         | 
| 562 | 
            -
                       | 
| 563 | 
            -
                       | 
| 564 | 
            -
                       | 
| 565 | 
            -
                       | 
| 582 | 
            +
                    sig { params(signature: T.untyped, parameters: T::Array[[Symbol, String]]).returns(String) }
         | 
| 583 | 
            +
                    def compile_signature(signature, parameters)
         | 
| 584 | 
            +
                      parameter_types = T.let(signature.arg_types.to_h, T::Hash[Symbol, T::Types::Base])
         | 
| 585 | 
            +
                      parameter_types.merge!(signature.kwarg_types)
         | 
| 586 | 
            +
                      parameter_types[signature.rest_name] = signature.rest_type if signature.has_rest
         | 
| 587 | 
            +
                      parameter_types[signature.keyrest_name] = signature.keyrest_type if signature.has_keyrest
         | 
| 588 | 
            +
                      parameter_types[signature.block_name] = signature.block_type if signature.block_name
         | 
| 566 589 |  | 
| 567 | 
            -
                      params =  | 
| 568 | 
            -
             | 
| 590 | 
            +
                      params = parameters.map do |_, name|
         | 
| 591 | 
            +
                        type = parameter_types[name.to_sym]
         | 
| 592 | 
            +
                        "#{name}: #{type}"
         | 
| 593 | 
            +
                      end.join(", ")
         | 
| 594 | 
            +
             | 
| 595 | 
            +
                      returns = type_of(signature.return_type)
         | 
| 569 596 |  | 
| 570 597 | 
             
                      type_parameters = (params + returns).scan(TYPE_PARAMETER_MATCHER).flatten.uniq.map { |p| ":#{p}" }.join(", ")
         | 
| 571 598 | 
             
                      type_parameters = ".type_parameters(#{type_parameters})" unless type_parameters.empty?
         | 
| @@ -591,6 +618,7 @@ module Tapioca | |
| 591 618 | 
             
                      signature_body = signature_body
         | 
| 592 619 | 
             
                        .gsub(".returns(<VOID>)", ".void")
         | 
| 593 620 | 
             
                        .gsub("<NOT-TYPED>", "T.untyped")
         | 
| 621 | 
            +
                        .gsub(".params()", "")
         | 
| 594 622 | 
             
                        .gsub(TYPE_PARAMETER_MATCHER, "T.type_parameter(:\\1)")[1..-1]
         | 
| 595 623 |  | 
| 596 624 | 
             
                      "sig { #{signature_body} }"
         | 
| @@ -784,6 +812,11 @@ module Tapioca | |
| 784 812 | 
             
                      nil
         | 
| 785 813 | 
             
                    end
         | 
| 786 814 |  | 
| 815 | 
            +
                    sig { params(constant: Module).returns(String) }
         | 
| 816 | 
            +
                    def type_of(constant)
         | 
| 817 | 
            +
                      constant.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
         | 
| 818 | 
            +
                    end
         | 
| 819 | 
            +
             | 
| 787 820 | 
             
                    sig { params(constant: Module, other: BasicObject).returns(T::Boolean).checked(:never) }
         | 
| 788 821 | 
             
                    def are_equal?(constant, other)
         | 
| 789 822 | 
             
                      BasicObject.instance_method(:equal?).bind(constant).call(other)
         | 
| @@ -1,7 +1,9 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            class Class
         | 
| 5 | 
            +
              extend T::Sig
         | 
| 6 | 
            +
             | 
| 5 7 | 
             
              # Returns an array with all classes that are < than its receiver.
         | 
| 6 8 | 
             
              #
         | 
| 7 9 | 
             
              #   class C; end
         | 
| @@ -15,9 +17,12 @@ class Class | |
| 15 17 | 
             
              #
         | 
| 16 18 | 
             
              #   class D < C; end
         | 
| 17 19 | 
             
              #   C.descendants # => [B, A, D]
         | 
| 20 | 
            +
              sig { returns(T::Array[Class]) }
         | 
| 18 21 | 
             
              def descendants
         | 
| 19 | 
            -
                ObjectSpace.each_object(singleton_class).reject do |k|
         | 
| 20 | 
            -
                  k.singleton_class? || k == self
         | 
| 22 | 
            +
                result = ObjectSpace.each_object(singleton_class).reject do |k|
         | 
| 23 | 
            +
                  T.cast(k, Module).singleton_class? || k == self
         | 
| 21 24 | 
             
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                T.cast(result, T::Array[Class])
         | 
| 22 27 | 
             
              end
         | 
| 23 28 | 
             
            end
         | 
    
        data/lib/tapioca/gemfile.rb
    CHANGED
    
    
    
        data/lib/tapioca/generator.rb
    CHANGED
    
    
    
        data/lib/tapioca/loader.rb
    CHANGED
    
    
    
        data/lib/tapioca/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: tapioca
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.4. | 
| 4 | 
            +
              version: 0.4.8
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ufuk Kayserilioglu
         | 
| @@ -11,7 +11,7 @@ authors: | |
| 11 11 | 
             
            autorequire: 
         | 
| 12 12 | 
             
            bindir: exe
         | 
| 13 13 | 
             
            cert_chain: []
         | 
| 14 | 
            -
            date: 2020- | 
| 14 | 
            +
            date: 2020-11-05 00:00:00.000000000 Z
         | 
| 15 15 | 
             
            dependencies:
         | 
| 16 16 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 17 17 | 
             
              name: pry
         | 
| @@ -69,6 +69,20 @@ dependencies: | |
| 69 69 | 
             
                - - ">="
         | 
| 70 70 | 
             
                  - !ruby/object:Gem::Version
         | 
| 71 71 | 
             
                    version: 2.1.0
         | 
| 72 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 73 | 
            +
              name: spoom
         | 
| 74 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 75 | 
            +
                requirements:
         | 
| 76 | 
            +
                - - ">="
         | 
| 77 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 78 | 
            +
                    version: '0'
         | 
| 79 | 
            +
              type: :runtime
         | 
| 80 | 
            +
              prerelease: false
         | 
| 81 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 82 | 
            +
                requirements:
         | 
| 83 | 
            +
                - - ">="
         | 
| 84 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 85 | 
            +
                    version: '0'
         | 
| 72 86 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 73 87 | 
             
              name: thor
         | 
| 74 88 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -127,7 +141,6 @@ files: | |
| 127 141 | 
             
            - lib/tapioca/gemfile.rb
         | 
| 128 142 | 
             
            - lib/tapioca/generator.rb
         | 
| 129 143 | 
             
            - lib/tapioca/loader.rb
         | 
| 130 | 
            -
            - lib/tapioca/sorbet_config_parser.rb
         | 
| 131 144 | 
             
            - lib/tapioca/version.rb
         | 
| 132 145 | 
             
            homepage: https://github.com/Shopify/tapioca
         | 
| 133 146 | 
             
            licenses:
         | 
| @@ -142,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 142 155 | 
             
              requirements:
         | 
| 143 156 | 
             
              - - ">="
         | 
| 144 157 | 
             
                - !ruby/object:Gem::Version
         | 
| 145 | 
            -
                  version: 2. | 
| 158 | 
            +
                  version: '2.4'
         | 
| 146 159 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 147 160 | 
             
              requirements:
         | 
| 148 161 | 
             
              - - ">="
         | 
| @@ -1,77 +0,0 @@ | |
| 1 | 
            -
            # typed: strict
         | 
| 2 | 
            -
            # frozen_string_literal: true
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            module Tapioca
         | 
| 5 | 
            -
              class SorbetConfig
         | 
| 6 | 
            -
                extend T::Sig
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                sig { returns(T::Array[String]) }
         | 
| 9 | 
            -
                attr_reader :paths, :ignore
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                sig { void }
         | 
| 12 | 
            -
                def initialize
         | 
| 13 | 
            -
                  @paths = T.let([], T::Array[String])
         | 
| 14 | 
            -
                  @ignore = T.let([], T::Array[String])
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                class << self
         | 
| 18 | 
            -
                  extend T::Sig
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                  sig { params(sorbet_config_path: String).returns(SorbetConfig) }
         | 
| 21 | 
            -
                  def parse_file(sorbet_config_path)
         | 
| 22 | 
            -
                    parse_string(File.read(sorbet_config_path))
         | 
| 23 | 
            -
                  end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  sig { params(sorbet_config: String).returns(SorbetConfig) }
         | 
| 26 | 
            -
                  def parse_string(sorbet_config)
         | 
| 27 | 
            -
                    config = SorbetConfig.new
         | 
| 28 | 
            -
                    ignore = T.let(false, T::Boolean)
         | 
| 29 | 
            -
                    skip = T.let(false, T::Boolean)
         | 
| 30 | 
            -
                    sorbet_config.each_line do |line|
         | 
| 31 | 
            -
                      line = line.strip
         | 
| 32 | 
            -
                      case line
         | 
| 33 | 
            -
                      when /^--ignore$/
         | 
| 34 | 
            -
                        ignore = true
         | 
| 35 | 
            -
                        next
         | 
| 36 | 
            -
                      when /^--ignore=/
         | 
| 37 | 
            -
                        config.ignore << parse_option(line)
         | 
| 38 | 
            -
                        next
         | 
| 39 | 
            -
                      when /^--file$/
         | 
| 40 | 
            -
                        next
         | 
| 41 | 
            -
                      when /^--file=/
         | 
| 42 | 
            -
                        config.paths << parse_option(line)
         | 
| 43 | 
            -
                        next
         | 
| 44 | 
            -
                      when /^--dir$/
         | 
| 45 | 
            -
                        next
         | 
| 46 | 
            -
                      when /^--dir=/
         | 
| 47 | 
            -
                        config.paths << parse_option(line)
         | 
| 48 | 
            -
                        next
         | 
| 49 | 
            -
                      when /^--.*=/
         | 
| 50 | 
            -
                        next
         | 
| 51 | 
            -
                      when /^--/
         | 
| 52 | 
            -
                        skip = true
         | 
| 53 | 
            -
                      when /^-.*=?/
         | 
| 54 | 
            -
                        next
         | 
| 55 | 
            -
                      else
         | 
| 56 | 
            -
                        if ignore
         | 
| 57 | 
            -
                          config.ignore << line
         | 
| 58 | 
            -
                          ignore = false
         | 
| 59 | 
            -
                        elsif skip
         | 
| 60 | 
            -
                          skip = false
         | 
| 61 | 
            -
                        else
         | 
| 62 | 
            -
                          config.paths << line
         | 
| 63 | 
            -
                        end
         | 
| 64 | 
            -
                      end
         | 
| 65 | 
            -
                    end
         | 
| 66 | 
            -
                    config
         | 
| 67 | 
            -
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  private
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                  sig { params(line: String).returns(String) }
         | 
| 72 | 
            -
                  def parse_option(line)
         | 
| 73 | 
            -
                    T.must(line.split("=").last).strip
         | 
| 74 | 
            -
                  end
         | 
| 75 | 
            -
                end
         | 
| 76 | 
            -
              end
         | 
| 77 | 
            -
            end
         |