tapioca 0.5.0 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Generators
6
+ class Init < Base
7
+ sig do
8
+ params(
9
+ sorbet_config: String,
10
+ default_postrequire: String,
11
+ default_command: String,
12
+ file_writer: Thor::Actions
13
+ ).void
14
+ end
15
+ def initialize(sorbet_config:, default_postrequire:, default_command:, file_writer: FileWriter.new)
16
+ @sorbet_config = sorbet_config
17
+ @default_postrequire = default_postrequire
18
+
19
+ super(default_command: default_command, file_writer: file_writer)
20
+
21
+ @installer = T.let(nil, T.nilable(Bundler::Installer))
22
+ @spec = T.let(nil, T.nilable(Bundler::StubSpecification))
23
+ end
24
+
25
+ sig { override.void }
26
+ def generate
27
+ create_config
28
+ create_post_require
29
+ if File.exist?(@default_command)
30
+ generate_binstub!
31
+ else
32
+ generate_binstub
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ sig { void }
39
+ def create_config
40
+ create_file(@sorbet_config, <<~CONTENT, skip: true, force: false)
41
+ --dir
42
+ .
43
+ CONTENT
44
+ end
45
+
46
+ sig { void }
47
+ def create_post_require
48
+ create_file(@default_postrequire, <<~CONTENT, skip: true, force: false)
49
+ # typed: true
50
+ # frozen_string_literal: true
51
+
52
+ # Add your extra requires here (`#{@default_command} require` can be used to boostrap this list)
53
+ CONTENT
54
+ end
55
+
56
+ sig { void }
57
+ def generate_binstub!
58
+ installer.generate_bundler_executable_stubs(spec, { force: true })
59
+ say_status(:force, @default_command, :yellow)
60
+ end
61
+
62
+ sig { void }
63
+ def generate_binstub
64
+ installer.generate_bundler_executable_stubs(spec)
65
+ say_status(:create, @default_command, :green)
66
+ end
67
+
68
+ sig { returns(Bundler::Installer) }
69
+ def installer
70
+ @installer ||= Bundler::Installer.new(Bundler.root, Bundler.definition)
71
+ end
72
+
73
+ sig { returns(Bundler::StubSpecification) }
74
+ def spec
75
+ @spec ||= Bundler.definition.specs.find { |s| s.name == "tapioca" }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,52 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Generators
6
+ class Require < Base
7
+ sig do
8
+ params(
9
+ requires_path: String,
10
+ sorbet_config_path: String,
11
+ default_command: String,
12
+ file_writer: Thor::Actions
13
+ ).void
14
+ end
15
+ def initialize(requires_path:, sorbet_config_path:, default_command:, file_writer: FileWriter.new)
16
+ @requires_path = requires_path
17
+ @sorbet_config_path = sorbet_config_path
18
+
19
+ super(default_command: default_command, file_writer: file_writer)
20
+ end
21
+
22
+ sig { override.void }
23
+ def generate
24
+ compiler = Compilers::RequiresCompiler.new(@sorbet_config_path)
25
+ name = set_color(@requires_path, :yellow, :bold)
26
+ say("Compiling #{name}, this may take a few seconds... ")
27
+
28
+ rb_string = compiler.compile
29
+ if rb_string.empty?
30
+ say("Nothing to do", :green)
31
+ return
32
+ end
33
+
34
+ # Clean all existing requires before regenerating the list so we update
35
+ # it with the new one found in the client code and remove the old ones.
36
+ File.delete(@requires_path) if File.exist?(@requires_path)
37
+
38
+ content = +"# typed: true\n"
39
+ content << "# frozen_string_literal: true\n\n"
40
+ content << rb_string
41
+
42
+ create_file(@requires_path, content, verbose: false)
43
+
44
+ say("Done", :green)
45
+
46
+ say("All requires from this application have been written to #{name}.", [:green, :bold])
47
+ cmd = set_color("#{@default_command} gem", :yellow, :bold)
48
+ say("Please review changes and commit them, then run `#{cmd}`.", [:green, :bold])
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,76 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Generators
6
+ class Todo < Base
7
+ sig do
8
+ params(
9
+ todos_path: String,
10
+ file_header: T::Boolean,
11
+ default_command: String,
12
+ file_writer: Thor::Actions
13
+ ).void
14
+ end
15
+ def initialize(todos_path:, file_header:, default_command:, file_writer: FileWriter.new)
16
+ @todos_path = todos_path
17
+ @file_header = file_header
18
+
19
+ super(default_command: default_command, file_writer: file_writer)
20
+ end
21
+
22
+ sig { override.void }
23
+ def generate
24
+ compiler = Compilers::TodosCompiler.new
25
+ say("Finding all unresolved constants, this may take a few seconds... ")
26
+
27
+ # Clean all existing unresolved constants before regenerating the list
28
+ # so Sorbet won't grab them as already resolved.
29
+ File.delete(@todos_path) if File.exist?(@todos_path)
30
+
31
+ rbi_string = compiler.compile
32
+ if rbi_string.empty?
33
+ say("Nothing to do", :green)
34
+ return
35
+ end
36
+
37
+ content = String.new
38
+ content << rbi_header(
39
+ "#{@default_command} todo",
40
+ reason: "unresolved constants",
41
+ strictness: "false"
42
+ )
43
+ content << rbi_string
44
+ content << "\n"
45
+
46
+ say("Done", :green)
47
+ create_file(@todos_path, content, verbose: false)
48
+
49
+ name = set_color(@todos_path, :yellow, :bold)
50
+ say("\nAll unresolved constants have been written to #{name}.", [:green, :bold])
51
+ say("Please review changes and commit them.", [:green, :bold])
52
+ end
53
+
54
+ sig { params(command: String, reason: T.nilable(String), strictness: T.nilable(String)).returns(String) }
55
+ def rbi_header(command, reason: nil, strictness: nil)
56
+ statement = <<~HEAD
57
+ # DO NOT EDIT MANUALLY
58
+ # This is an autogenerated file for #{reason}.
59
+ # Please instead update this file by running `#{command}`.
60
+ HEAD
61
+
62
+ sigil = <<~SIGIL if strictness
63
+ # typed: #{strictness}
64
+ SIGIL
65
+
66
+ if @file_header
67
+ [statement, sigil].compact.join("\n").strip.concat("\n\n")
68
+ elsif sigil
69
+ sigil.strip.concat("\n\n")
70
+ else
71
+ ""
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "generators/base"
5
+ require_relative "generators/dsl"
6
+ require_relative "generators/init"
7
+ require_relative "generators/gem"
8
+ require_relative "generators/require"
9
+ require_relative "generators/todo"
@@ -3,13 +3,12 @@
3
3
 
4
4
  require "tapioca"
5
5
  require "tapioca/loader"
6
- require "tapioca/constant_locator"
7
6
  require "tapioca/sorbet_ext/generic_name_patch"
8
7
  require "tapioca/sorbet_ext/fixed_hash_patch"
9
8
  require "tapioca/generic_type_registry"
10
9
  require "tapioca/config"
11
10
  require "tapioca/config_builder"
12
- require "tapioca/generator"
11
+ require "tapioca/generators"
13
12
  require "tapioca/cli"
14
13
  require "tapioca/gemfile"
15
14
  require "tapioca/compilers/sorbet"
@@ -9,10 +9,10 @@ module Tapioca
9
9
  def load_bundle(gemfile, initialize_file, require_file)
10
10
  require_helper(initialize_file)
11
11
 
12
- gemfile.require_bundle
13
-
14
12
  load_rails_application
15
13
 
14
+ gemfile.require_bundle
15
+
16
16
  require_helper(require_file)
17
17
 
18
18
  load_rails_engines
@@ -4,6 +4,50 @@
4
4
  require "rbi"
5
5
 
6
6
  module RBI
7
+ class File
8
+ extend T::Sig
9
+
10
+ sig { returns(String) }
11
+ def transformed_string
12
+ transform_rbi!
13
+ string
14
+ end
15
+
16
+ sig { void }
17
+ def transform_rbi!
18
+ root.nest_singleton_methods!
19
+ root.nest_non_public_methods!
20
+ root.group_nodes!
21
+ root.sort_nodes!
22
+ end
23
+
24
+ sig do
25
+ params(
26
+ command: String,
27
+ reason: T.nilable(String),
28
+ display_heading: T::Boolean
29
+ ).void
30
+ end
31
+ def set_file_header(command, reason: nil, display_heading: true)
32
+ return unless display_heading
33
+ comments << RBI::Comment.new("DO NOT EDIT MANUALLY")
34
+ comments << RBI::Comment.new("This is an autogenerated file for #{reason}.") unless reason.nil?
35
+ comments << RBI::Comment.new("Please instead update this file by running `#{command}`.")
36
+ end
37
+
38
+ sig { void }
39
+ def set_empty_body_content
40
+ comments << RBI::EmptyComment.new unless comments.empty?
41
+ comments << RBI::Comment.new("THIS IS AN EMPTY RBI FILE.")
42
+ comments << RBI::Comment.new("see https://github.com/Shopify/tapioca/wiki/Manual-Gem-Requires")
43
+ end
44
+
45
+ sig { returns(T::Boolean) }
46
+ def empty?
47
+ root.empty?
48
+ end
49
+ end
50
+
7
51
  class Tree
8
52
  extend T::Sig
9
53
 
@@ -17,6 +17,7 @@ module Tapioca
17
17
  PUBLIC_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:public_instance_methods), UnboundMethod)
18
18
  PROTECTED_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:protected_instance_methods), UnboundMethod)
19
19
  PRIVATE_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:private_instance_methods), UnboundMethod)
20
+ METHOD_METHOD = T.let(Kernel.instance_method(:method), UnboundMethod)
20
21
 
21
22
  sig { params(object: BasicObject).returns(Class).checked(:never) }
22
23
  def class_of(object)
@@ -30,7 +31,8 @@ module Tapioca
30
31
 
31
32
  sig { params(constant: Module).returns(T.nilable(String)) }
32
33
  def name_of(constant)
33
- NAME_METHOD.bind(constant).call
34
+ name = NAME_METHOD.bind(constant).call
35
+ name&.start_with?("#<") ? nil : name
34
36
  end
35
37
 
36
38
  sig { params(constant: Module).returns(Class) }
@@ -106,6 +108,11 @@ module Tapioca
106
108
  type.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
107
109
  end
108
110
 
111
+ sig { params(constant: Module, method: Symbol).returns(Method) }
112
+ def method_of(constant, method)
113
+ METHOD_METHOD.bind(constant).call(method)
114
+ end
115
+
109
116
  # Returns an array with all classes that are < than the supplied class.
110
117
  #
111
118
  # class C; end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.5.0"
5
+ VERSION = "0.5.4"
6
6
  end
data/lib/tapioca.rb CHANGED
@@ -18,6 +18,8 @@ module Tapioca
18
18
  end
19
19
 
20
20
  require "tapioca/reflection"
21
+ require "tapioca/constant_locator"
21
22
  require "tapioca/compilers/dsl/base"
23
+ require "tapioca/compilers/dynamic_mixin_compiler"
22
24
  require "tapioca/helpers/active_record_column_type_helper"
23
25
  require "tapioca/version"
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.5.0
4
+ version: 0.5.4
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: 2021-09-07 00:00:00.000000000 Z
14
+ date: 2021-10-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -61,14 +61,14 @@ dependencies:
61
61
  requirements:
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
- version: 0.4.4471
64
+ version: 0.5.6200
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: 0.4.4471
71
+ version: 0.5.6200
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: sorbet-runtime
74
74
  requirement: !ruby/object:Gem::Requirement
@@ -112,7 +112,7 @@ dependencies:
112
112
  - !ruby/object:Gem::Version
113
113
  version: 0.19.2
114
114
  - !ruby/object:Gem::Dependency
115
- name: unparser
115
+ name: yard-sorbet
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - ">="
@@ -144,9 +144,11 @@ files:
144
144
  - lib/tapioca/compilers/dsl/action_mailer.rb
145
145
  - lib/tapioca/compilers/dsl/active_job.rb
146
146
  - lib/tapioca/compilers/dsl/active_model_attributes.rb
147
+ - lib/tapioca/compilers/dsl/active_model_secure_password.rb
147
148
  - lib/tapioca/compilers/dsl/active_record_associations.rb
148
149
  - lib/tapioca/compilers/dsl/active_record_columns.rb
149
150
  - lib/tapioca/compilers/dsl/active_record_enum.rb
151
+ - lib/tapioca/compilers/dsl/active_record_fixtures.rb
150
152
  - lib/tapioca/compilers/dsl/active_record_scope.rb
151
153
  - lib/tapioca/compilers/dsl/active_record_typed_store.rb
152
154
  - lib/tapioca/compilers/dsl/active_resource.rb
@@ -157,12 +159,14 @@ files:
157
159
  - lib/tapioca/compilers/dsl/config.rb
158
160
  - lib/tapioca/compilers/dsl/frozen_record.rb
159
161
  - lib/tapioca/compilers/dsl/identity_cache.rb
162
+ - lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb
160
163
  - lib/tapioca/compilers/dsl/protobuf.rb
161
164
  - lib/tapioca/compilers/dsl/sidekiq_worker.rb
162
165
  - lib/tapioca/compilers/dsl/smart_properties.rb
163
166
  - lib/tapioca/compilers/dsl/state_machines.rb
164
167
  - lib/tapioca/compilers/dsl/url_helpers.rb
165
168
  - lib/tapioca/compilers/dsl_compiler.rb
169
+ - lib/tapioca/compilers/dynamic_mixin_compiler.rb
166
170
  - lib/tapioca/compilers/requires_compiler.rb
167
171
  - lib/tapioca/compilers/sorbet.rb
168
172
  - lib/tapioca/compilers/symbol_table/symbol_generator.rb
@@ -173,7 +177,13 @@ files:
173
177
  - lib/tapioca/config_builder.rb
174
178
  - lib/tapioca/constant_locator.rb
175
179
  - lib/tapioca/gemfile.rb
176
- - lib/tapioca/generator.rb
180
+ - lib/tapioca/generators.rb
181
+ - lib/tapioca/generators/base.rb
182
+ - lib/tapioca/generators/dsl.rb
183
+ - lib/tapioca/generators/gem.rb
184
+ - lib/tapioca/generators/init.rb
185
+ - lib/tapioca/generators/require.rb
186
+ - lib/tapioca/generators/todo.rb
177
187
  - lib/tapioca/generic_type_registry.rb
178
188
  - lib/tapioca/helpers/active_record_column_type_helper.rb
179
189
  - lib/tapioca/internal.rb