tapioca 0.4.13 → 0.4.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce4d47f5c9b44a027ecd554533420b2a567ba3353cc073b85498fb86522a56ba
4
- data.tar.gz: abee7797626806d015d410423a4f929875076f58f5e4859a2567a3f2921424bd
3
+ metadata.gz: b3709ab7f54589bdf97715ffc2cc7c3a98ad703a6e318a264db70429078cdf26
4
+ data.tar.gz: 3e38366a54f9b3286de28a2b6d557762b2cf564848b8184a76aadc75504a41fb
5
5
  SHA512:
6
- metadata.gz: 1370fc47539d7f9504796faddcc71f08c0ecccd8b9af8623ab2a4496eef8e94f535aeb4e7266149a0e759e9115dfa0a062a57ea77db412e366ac07436912ae82
7
- data.tar.gz: 9761bc6237bb0702e33cbca95e6f896c6ee07dc0efbec8a99d09493b551e162b28c63439320afeed56c6efec07b00621c54f245ab3b88011fe988dab1e2ac5c8
6
+ metadata.gz: 4ef5e31a85a71607340ad54e2fff59b1a5bd0d3f81b1481bd4830ca5e73e5ea9ed1504d38808d8bf49a9686276685167a35103769fdb30d66b61362c4d9c072b
7
+ data.tar.gz: e0b1daab32f024cc5f3f1fc019b5c1dcd040ce0657e59b81d736702e3cb380a9e7265397f108f4787163e50d9b31e793b960cd33f875cf45a061cee17fa1857e
data/Gemfile CHANGED
@@ -10,7 +10,6 @@ group(:deployment, :development) do
10
10
  gem("rake")
11
11
  end
12
12
 
13
- gem("bundler", "~> 1.17")
14
13
  gem("yard", "~> 0.9.25")
15
14
  gem("pry-byebug")
16
15
  gem("minitest")
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ > :warning: **Note**: This software is currently under active development. The API and interface should be considered unstable until a v1.0.0 release.
2
+
1
3
  # Tapioca
2
4
 
3
5
  ![Build Status](https://github.com/Shopify/tapioca/workflows/CI/badge.svg)
@@ -14,7 +16,7 @@ For gems that have a normal default `require` and load all of their constants th
14
16
 
15
17
  For example, suppose you are using the class `BetterHtml::Parser` exported from the `better_html` gem. Just doing a `require "better_html"` (which is the default require) does not load that type:
16
18
 
17
- ```ruby
19
+ ```shell
18
20
  $ bundle exec pry
19
21
  [1] pry(main)> require 'better_html'
20
22
  => true
@@ -110,7 +112,7 @@ This will generate DSL RBIs for specified constants (or for all handled constant
110
112
  - `--prerequire [file]`: A file to be required before `Bundler.require` is called.
111
113
  - `--postrequire [file]`: A file to be required after `Bundler.require` is called.
112
114
  - `--out [directory]`: The output directory for generated RBI files, default to `sorbet/rbi/gems`.
113
- - `--generate-command [command]`: The command to run to regenerate RBI files (used in header comment of the RBI files), defaults to the current command.
115
+ - `--generate-command [command]`: **[DEPRECATED]** The command to run to regenerate RBI files (used in header comment of the RBI files), defaults to the current command.
114
116
  - `--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).
115
117
 
116
118
  ## Contributing
data/exe/tapioca CHANGED
@@ -1,6 +1,21 @@
1
1
  #! /usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "../lib/tapioca"
4
+ require 'sorbet-runtime'
5
5
 
6
- Tapioca::Cli.start(ARGV)
6
+ begin
7
+ T::Configuration.default_checked_level = :never
8
+ # Suppresses errors caused by T.cast, T.let, T.must, etc.
9
+ T::Configuration.inline_type_error_handler = ->(*) {}
10
+ # Suppresses errors caused by incorrect parameter ordering
11
+ T::Configuration.sig_validation_error_handler = ->(*) {}
12
+ rescue
13
+ # Need this rescue so that if another gem has
14
+ # already set the checked level by the time we
15
+ # get to it, we don't fail outright.
16
+ nil
17
+ end
18
+
19
+ require_relative "../lib/tapioca/internal"
20
+
21
+ Tapioca::Cli::Main.start(ARGV)
data/lib/tapioca.rb CHANGED
@@ -17,31 +17,5 @@ module Tapioca
17
17
  class Error < StandardError; end
18
18
  end
19
19
 
20
- begin
21
- T::Configuration.default_checked_level = :never
22
- # Suppresses errors caused by T.cast, T.let, T.must, etc.
23
- T::Configuration.inline_type_error_handler = ->(*) {}
24
- # Suppresses errors caused by incorrect parameter ordering
25
- T::Configuration.sig_validation_error_handler = ->(*) {}
26
- rescue
27
- # Need this rescue so that if another gem has
28
- # already set the checked level by the time we
29
- # get to it, we don't fail outright.
30
- nil
31
- end
32
-
33
- require "tapioca/loader"
34
- require "tapioca/constant_locator"
35
- require "tapioca/config"
36
- require "tapioca/config_builder"
37
- require "tapioca/generator"
38
- require "tapioca/cli"
39
- require "tapioca/gemfile"
40
- require "tapioca/compilers/sorbet"
41
- require "tapioca/compilers/requires_compiler"
42
- require "tapioca/compilers/symbol_table_compiler"
43
- require "tapioca/compilers/symbol_table/symbol_generator"
44
- require "tapioca/compilers/symbol_table/symbol_loader"
45
- require "tapioca/compilers/todos_compiler"
46
- require "tapioca/compilers/dsl_compiler"
20
+ require "tapioca/compilers/dsl/base"
47
21
  require "tapioca/version"
data/lib/tapioca/cli.rb CHANGED
@@ -4,112 +4,5 @@
4
4
  require 'thor'
5
5
 
6
6
  module Tapioca
7
- class Cli < Thor
8
- include(Thor::Actions)
9
-
10
- class_option :prerequire,
11
- aliases: ["--pre", "-b"],
12
- banner: "file",
13
- desc: "A file to be required before Bundler.require is called"
14
- class_option :postrequire,
15
- aliases: ["--post", "-a"],
16
- banner: "file",
17
- desc: "A file to be required after Bundler.require is called"
18
- class_option :outdir,
19
- aliases: ["--out", "-o"],
20
- banner: "directory",
21
- desc: "The output directory for generated RBI files"
22
- class_option :generate_command,
23
- aliases: ["--cmd", "-c"],
24
- banner: "command",
25
- desc: "The command to run to regenerate RBI files"
26
- class_option :exclude,
27
- aliases: ["-x"],
28
- type: :array,
29
- banner: "gem [gem ...]",
30
- desc: "Excludes the given gem(s) from RBI generation"
31
- class_option :typed_overrides,
32
- aliases: ["--typed", "-t"],
33
- type: :hash,
34
- banner: "gem:level [gem:level ...]",
35
- desc: "Overrides for typed sigils for generated gem RBIs"
36
-
37
- map T.unsafe(%w[--version -v] => :__print_version)
38
-
39
- desc "init", "initializes folder structure"
40
- def init
41
- create_file(Config::SORBET_CONFIG, skip: true) do
42
- <<~CONTENT
43
- --dir
44
- .
45
- CONTENT
46
- end
47
- create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do
48
- <<~CONTENT
49
- # typed: false
50
- # frozen_string_literal: true
51
-
52
- # Add your extra requires here
53
- CONTENT
54
- end
55
- end
56
-
57
- desc "require", "generate the list of files to be required by tapioca"
58
- def require
59
- Tapioca.silence_warnings do
60
- generator.build_requires
61
- end
62
- end
63
-
64
- desc "todo", "generate the list of unresolved constants"
65
- def todo
66
- Tapioca.silence_warnings do
67
- generator.build_todos
68
- end
69
- end
70
-
71
- desc "dsl [constant...]", "generate RBIs for dynamic methods"
72
- option :generators,
73
- type: :array,
74
- aliases: ["--gen", "-g"],
75
- banner: "generator [generator ...]",
76
- desc: "Only run supplied DSL generators"
77
- def dsl(*constants)
78
- Tapioca.silence_warnings do
79
- generator.build_dsl(constants)
80
- end
81
- end
82
-
83
- desc "generate [gem...]", "generate RBIs from gems"
84
- def generate(*gems)
85
- Tapioca.silence_warnings do
86
- generator.build_gem_rbis(gems)
87
- end
88
- end
89
-
90
- desc "sync", "sync RBIs to Gemfile"
91
- def sync
92
- Tapioca.silence_warnings do
93
- generator.sync_rbis_with_gemfile
94
- end
95
- end
96
-
97
- desc "--version, -v", "show version"
98
- def __print_version
99
- puts "Tapioca v#{Tapioca::VERSION}"
100
- end
101
-
102
- no_commands do
103
- def self.exit_on_failure?
104
- true
105
- end
106
-
107
- def generator
108
- current_command = T.must(current_command_chain.first)
109
- @generator ||= Generator.new(
110
- ConfigBuilder.from_options(current_command, options)
111
- )
112
- end
113
- end
114
- end
7
+ module Cli; end
115
8
  end
@@ -0,0 +1,136 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Cli
6
+ class Main < Thor
7
+ include(Thor::Actions)
8
+
9
+ class_option :prerequire,
10
+ aliases: ["--pre", "-b"],
11
+ banner: "file",
12
+ desc: "A file to be required before Bundler.require is called"
13
+ class_option :postrequire,
14
+ aliases: ["--post", "-a"],
15
+ banner: "file",
16
+ desc: "A file to be required after Bundler.require is called"
17
+ class_option :outdir,
18
+ aliases: ["--out", "-o"],
19
+ banner: "directory",
20
+ desc: "The output directory for generated RBI files"
21
+ class_option :generate_command,
22
+ aliases: ["--cmd", "-c"],
23
+ banner: "command",
24
+ desc: "The command to run to regenerate RBI files"
25
+ class_option :exclude,
26
+ aliases: ["-x"],
27
+ type: :array,
28
+ banner: "gem [gem ...]",
29
+ desc: "Excludes the given gem(s) from RBI generation"
30
+ class_option :typed_overrides,
31
+ aliases: ["--typed", "-t"],
32
+ type: :hash,
33
+ banner: "gem:level [gem:level ...]",
34
+ desc: "Overrides for typed sigils for generated gem RBIs"
35
+
36
+ map T.unsafe(%w[--version -v] => :__print_version)
37
+
38
+ desc "init", "initializes folder structure"
39
+ def init
40
+ create_config
41
+ create_post_require
42
+ generate_binstub
43
+ end
44
+
45
+ desc "require", "generate the list of files to be required by tapioca"
46
+ def require
47
+ Tapioca.silence_warnings do
48
+ generator.build_requires
49
+ end
50
+ end
51
+
52
+ desc "todo", "generate the list of unresolved constants"
53
+ def todo
54
+ Tapioca.silence_warnings do
55
+ generator.build_todos
56
+ end
57
+ end
58
+
59
+ desc "dsl [constant...]", "generate RBIs for dynamic methods"
60
+ option :generators,
61
+ type: :array,
62
+ aliases: ["--gen", "-g"],
63
+ banner: "generator [generator ...]",
64
+ desc: "Only run supplied DSL generators"
65
+ option :verify,
66
+ type: :boolean,
67
+ default: false,
68
+ desc: "Verifies RBIs are up-to-date"
69
+ def dsl(*constants)
70
+ Tapioca.silence_warnings do
71
+ generator.build_dsl(constants, should_verify: options[:verify])
72
+ end
73
+ end
74
+
75
+ desc "generate [gem...]", "generate RBIs from gems"
76
+ def generate(*gems)
77
+ Tapioca.silence_warnings do
78
+ generator.build_gem_rbis(gems)
79
+ end
80
+ end
81
+
82
+ desc "sync", "sync RBIs to Gemfile"
83
+ def sync
84
+ Tapioca.silence_warnings do
85
+ generator.sync_rbis_with_gemfile
86
+ end
87
+ end
88
+
89
+ desc "--version, -v", "show version"
90
+ def __print_version
91
+ puts "Tapioca v#{Tapioca::VERSION}"
92
+ end
93
+
94
+ private
95
+
96
+ def create_config
97
+ create_file(Config::SORBET_CONFIG, skip: true) do
98
+ <<~CONTENT
99
+ --dir
100
+ .
101
+ CONTENT
102
+ end
103
+ end
104
+
105
+ def create_post_require
106
+ create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do
107
+ <<~CONTENT
108
+ # typed: false
109
+ # frozen_string_literal: true
110
+
111
+ # Add your extra requires here
112
+ CONTENT
113
+ end
114
+ end
115
+
116
+ def generate_binstub
117
+ installer = Bundler::Installer.new(Bundler.root, Bundler.definition)
118
+ spec = Bundler.definition.specs.find { |s| s.name == "tapioca" }
119
+ installer.generate_bundler_executable_stubs(spec, { force: true })
120
+ end
121
+
122
+ no_commands do
123
+ def self.exit_on_failure?
124
+ true
125
+ end
126
+
127
+ def generator
128
+ current_command = T.must(current_command_chain.first)
129
+ @generator ||= Generator.new(
130
+ ConfigBuilder.from_options(current_command, options)
131
+ )
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -24,6 +24,8 @@ module Tapioca
24
24
  # belongs_to :category
25
25
  # has_many :comments
26
26
  # has_one :author, class_name: "User"
27
+ #
28
+ # accepts_nested_attributes_for :category, :comments, :author
27
29
  # end
28
30
  # ~~~
29
31
  #
@@ -44,6 +46,9 @@ module Tapioca
44
46
  # sig { params(value: T.nilable(::User)).void }
45
47
  # def author=(value); end
46
48
  #
49
+ # sig { params(attributes: T.untyped).returns(T.untyped) }
50
+ # def author_attributes=(attributes); end
51
+ #
47
52
  # sig { params(args: T.untyped, blk: T.untyped).returns(::User) }
48
53
  # def build_author(*args, &blk); end
49
54
  #
@@ -56,6 +61,9 @@ module Tapioca
56
61
  # sig { params(value: T.nilable(::Category)).void }
57
62
  # def category=(value); end
58
63
  #
64
+ # sig { params(attributes: T.untyped).returns(T.untyped) }
65
+ # def category_attributes=(attributes); end
66
+ #
59
67
  # sig { returns(T::Array[T.untyped]) }
60
68
  # def comment_ids; end
61
69
  #
@@ -68,6 +76,9 @@ module Tapioca
68
76
  # sig { params(value: T::Enumerable[::Comment]).void }
69
77
  # def comments=(value); end
70
78
  #
79
+ # sig { params(attributes: T.untyped).returns(T.untyped) }
80
+ # def comments_attributes=(attributes); end
81
+ #
71
82
  # sig { params(args: T.untyped, blk: T.untyped).returns(::User) }
72
83
  # def create_author(*args, &blk); end
73
84
  #
@@ -103,13 +114,8 @@ module Tapioca
103
114
  module_name = "GeneratedAssociationMethods"
104
115
 
105
116
  model.create_module(module_name) do |mod|
106
- constant.reflections.each do |association_name, reflection|
107
- if reflection.collection?
108
- populate_collection_assoc_getter_setter(mod, constant, association_name, reflection)
109
- else
110
- populate_single_assoc_getter_setter(mod, constant, association_name, reflection)
111
- end
112
- end
117
+ populate_nested_attribute_writers(mod, constant)
118
+ populate_associations(mod, constant)
113
119
  end
114
120
 
115
121
  model.create_include(module_name)
@@ -123,6 +129,31 @@ module Tapioca
123
129
 
124
130
  private
125
131
 
132
+ sig { params(mod: Parlour::RbiGenerator::Namespace, constant: T.class_of(ActiveRecord::Base)).void }
133
+ def populate_nested_attribute_writers(mod, constant)
134
+ constant.nested_attributes_options.keys.each do |association_name|
135
+ create_method(
136
+ mod,
137
+ "#{association_name}_attributes=",
138
+ parameters: [
139
+ Parlour::RbiGenerator::Parameter.new("attributes", type: "T.untyped"),
140
+ ],
141
+ return_type: "T.untyped"
142
+ )
143
+ end
144
+ end
145
+
146
+ sig { params(mod: Parlour::RbiGenerator::Namespace, constant: T.class_of(ActiveRecord::Base)).void }
147
+ def populate_associations(mod, constant)
148
+ constant.reflections.each do |association_name, reflection|
149
+ if reflection.collection?
150
+ populate_collection_assoc_getter_setter(mod, constant, association_name, reflection)
151
+ else
152
+ populate_single_assoc_getter_setter(mod, constant, association_name, reflection)
153
+ end
154
+ end
155
+ end
156
+
126
157
  sig do
127
158
  params(
128
159
  klass: Parlour::RbiGenerator::Namespace,
@@ -371,7 +371,6 @@ module Tapioca
371
371
  return unless signature
372
372
 
373
373
  return_type = signature.return_type
374
- return if T::Types::Simple === return_type && T::Generic === return_type.raw_type
375
374
  return if return_type == T::Private::Types::Void || return_type == T::Private::Types::NotTyped
376
375
 
377
376
  return_type.to_s
@@ -382,10 +381,11 @@ module Tapioca
382
381
  signature = T::Private::Methods.signature_for_method(column_type.method(method))
383
382
  return unless signature
384
383
 
385
- arg_type = signature.arg_types.first.last
386
- return if T::Types::Simple === arg_type && T::Generic === arg_type.raw_type
384
+ # Arg types is an array [name, type] entries, so we desctructure the type of
385
+ # first argument to get the first argument type
386
+ _, first_argument_type = signature.arg_types.first
387
387
 
388
- arg_type.to_s
388
+ first_argument_type.to_s
389
389
  end
390
390
 
391
391
  sig { params(type: String).returns(String) }