tapioca 0.5.0 → 0.5.4

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.
@@ -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