sorbet-rails 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +13 -1
  3. data/.travis.yml +2 -2
  4. data/Gemfile +1 -1
  5. data/README.md +79 -3
  6. data/lib/sorbet-rails.rb +5 -1
  7. data/lib/sorbet-rails/activerecord.rbi +27 -0
  8. data/lib/sorbet-rails/custom_finder_methods.rb +11 -0
  9. data/lib/sorbet-rails/helper_rbi_formatter.rb +33 -0
  10. data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +91 -0
  11. data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +111 -0
  12. data/lib/sorbet-rails/model_plugins/active_record_enum.rb +43 -0
  13. data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +80 -0
  14. data/lib/sorbet-rails/model_plugins/active_record_named_scope.rb +28 -0
  15. data/lib/sorbet-rails/model_plugins/active_record_querying.rb +42 -0
  16. data/lib/sorbet-rails/model_plugins/active_relation_where_not.rb +28 -0
  17. data/lib/sorbet-rails/model_plugins/base.rb +33 -0
  18. data/lib/sorbet-rails/model_plugins/custom_finder_methods.rb +54 -0
  19. data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +49 -0
  20. data/lib/sorbet-rails/model_plugins/plugins.rb +45 -0
  21. data/lib/sorbet-rails/model_rbi_formatter.rb +108 -362
  22. data/lib/sorbet-rails/model_utils.rb +45 -0
  23. data/lib/sorbet-rails/railtie.rb +1 -0
  24. data/lib/sorbet-rails/routes_rbi_formatter.rb +12 -3
  25. data/lib/sorbet-rails/tasks/rails_rbi.rake +36 -15
  26. data/lib/sorbet-rails/utils.rb +4 -0
  27. data/sorbet-rails.gemspec +4 -2
  28. data/spec/helper_rbi_formatter_spec.rb +13 -0
  29. data/spec/model_plugins_spec.rb +31 -0
  30. data/spec/model_rbi_formatter_spec.rb +5 -5
  31. data/spec/rake_rails_rbi_helpers_spec.rb +14 -0
  32. data/spec/routes_rbi_formatter_spec.rb +3 -3
  33. data/spec/sorbet_spec.rb +12 -16
  34. data/spec/support/rails_shared/app/controllers/application_controller.rb +1 -1
  35. data/spec/support/rails_shared/app/helpers/bar_helper.rb +2 -0
  36. data/spec/support/rails_shared/app/helpers/baz_helper.rb +2 -0
  37. data/spec/support/rails_shared/app/helpers/foo_helper.rb +2 -0
  38. data/spec/support/rails_shared/app/models/concerns/mythical.rb +10 -0
  39. data/spec/support/rails_shared/app/models/wand.rb +1 -0
  40. data/spec/support/rails_shared/config/initializers/sorbet_rails.rb +3 -0
  41. data/spec/support/rails_shared/lib/mythical_rbi_plugin.rb +16 -0
  42. data/spec/support/rails_shared/sorbet_test_cases.rb +5 -2
  43. data/spec/support/rails_shared/typed-override.yaml +2 -0
  44. data/spec/support/rails_symlinks/app/helpers +1 -0
  45. data/spec/support/rails_symlinks/config/initializers/sorbet_rails.rb +1 -0
  46. data/spec/support/rails_symlinks/lib/mythical_rbi_plugin.rb +1 -0
  47. data/spec/support/rails_symlinks/typed-override.yaml +1 -0
  48. data/spec/support/v4.2/Gemfile.lock +5 -0
  49. data/spec/support/v4.2/app/helpers +1 -0
  50. data/spec/support/v4.2/config/initializers/sorbet_rails.rb +1 -0
  51. data/spec/support/v4.2/config/routes.rb +0 -1
  52. data/spec/support/v4.2/lib/mythical_rbi_plugin.rb +1 -0
  53. data/spec/support/v4.2/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1 -1
  54. data/spec/support/v4.2/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1 -1
  55. data/spec/support/v4.2/typed-override.yaml +1 -0
  56. data/spec/support/v5.0/Gemfile.lock +5 -0
  57. data/spec/support/v5.0/app/helpers +1 -0
  58. data/spec/support/v5.0/config/initializers/sorbet_rails.rb +1 -0
  59. data/spec/support/v5.0/config/routes.rb +0 -1
  60. data/spec/support/v5.0/lib/mythical_rbi_plugin.rb +1 -0
  61. data/spec/support/v5.0/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1 -1
  62. data/spec/support/v5.0/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1 -1
  63. data/spec/support/v5.0/typed-override.yaml +1 -0
  64. data/spec/support/v5.1/Gemfile.lock +5 -0
  65. data/spec/support/v5.1/app/helpers +1 -0
  66. data/spec/support/v5.1/config/initializers/sorbet_rails.rb +1 -0
  67. data/spec/support/v5.1/lib/mythical_rbi_plugin.rb +1 -0
  68. data/spec/support/v5.1/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1 -1
  69. data/spec/support/v5.1/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1 -1
  70. data/spec/support/v5.1/typed-override.yaml +1 -0
  71. data/spec/support/v5.2-no-sorbet/Gemfile +0 -2
  72. data/spec/support/v5.2-no-sorbet/Gemfile.lock +7 -5
  73. data/spec/support/v5.2-no-sorbet/app/helpers +1 -0
  74. data/spec/support/v5.2-no-sorbet/config/initializers/sorbet_rails.rb +1 -0
  75. data/spec/support/v5.2-no-sorbet/lib/mythical_rbi_plugin.rb +1 -0
  76. data/spec/support/v5.2-no-sorbet/sorbet_test_cases.rb +1 -0
  77. data/spec/support/v5.2-no-sorbet/typed-override.yaml +1 -0
  78. data/spec/support/v5.2/Gemfile +0 -2
  79. data/spec/support/v5.2/Gemfile.lock +7 -5
  80. data/spec/support/v5.2/app/helpers +1 -0
  81. data/spec/support/v5.2/config/initializers/sorbet_rails.rb +1 -0
  82. data/spec/support/v5.2/lib/mythical_rbi_plugin.rb +1 -0
  83. data/spec/support/v5.2/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1 -1
  84. data/spec/support/v5.2/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1 -1
  85. data/spec/support/v5.2/typed-override.yaml +1 -0
  86. data/spec/support/v6.0/Gemfile +1 -3
  87. data/spec/support/v6.0/Gemfile.lock +61 -59
  88. data/spec/support/v6.0/app/helpers +1 -0
  89. data/spec/support/v6.0/config/initializers/sorbet_rails.rb +1 -0
  90. data/spec/support/v6.0/config/routes.rb +0 -1
  91. data/spec/support/v6.0/lib/mythical_rbi_plugin.rb +1 -0
  92. data/spec/support/v6.0/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1 -1
  93. data/spec/support/v6.0/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1 -1
  94. data/spec/support/v6.0/typed-override.yaml +1 -0
  95. data/spec/test_data/v4.2/expected_helpers.rbi +17 -0
  96. data/spec/test_data/v4.2/expected_potion.rbi +259 -28
  97. data/spec/test_data/v4.2/expected_spell_book.rbi +278 -37
  98. data/spec/test_data/v4.2/expected_srb_tc_output.txt +1 -99
  99. data/spec/test_data/v4.2/expected_wand.rbi +345 -96
  100. data/spec/test_data/v4.2/expected_wizard.rbi +322 -76
  101. data/spec/test_data/v4.2/expected_wizard_wo_spellbook.rbi +322 -76
  102. data/spec/test_data/v5.0/expected_helpers.rbi +17 -0
  103. data/spec/test_data/v5.0/expected_internal_metadata.rbi +273 -37
  104. data/spec/test_data/v5.0/expected_potion.rbi +259 -28
  105. data/spec/test_data/v5.0/expected_schema_migration.rbi +264 -28
  106. data/spec/test_data/v5.0/expected_spell_book.rbi +278 -37
  107. data/spec/test_data/v5.0/expected_srb_tc_output.txt +1 -81
  108. data/spec/test_data/v5.0/expected_wand.rbi +341 -92
  109. data/spec/test_data/v5.0/expected_wizard.rbi +318 -72
  110. data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +318 -72
  111. data/spec/test_data/v5.1/expected_helpers.rbi +17 -0
  112. data/spec/test_data/v5.1/expected_internal_metadata.rbi +273 -37
  113. data/spec/test_data/v5.1/expected_potion.rbi +259 -28
  114. data/spec/test_data/v5.1/expected_schema_migration.rbi +264 -28
  115. data/spec/test_data/v5.1/expected_spell_book.rbi +278 -37
  116. data/spec/test_data/v5.1/expected_srb_tc_output.txt +1 -81
  117. data/spec/test_data/v5.1/expected_wand.rbi +341 -92
  118. data/spec/test_data/v5.1/expected_wizard.rbi +318 -72
  119. data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +318 -72
  120. data/spec/test_data/v5.2-no-sorbet/expected_attachment.rbi +265 -29
  121. data/spec/test_data/v5.2-no-sorbet/expected_blob.rbi +271 -35
  122. data/spec/test_data/v5.2-no-sorbet/expected_helpers.rbi +17 -0
  123. data/spec/test_data/v5.2-no-sorbet/expected_internal_metadata.rbi +273 -37
  124. data/spec/test_data/v5.2-no-sorbet/expected_potion.rbi +259 -28
  125. data/spec/test_data/v5.2-no-sorbet/expected_schema_migration.rbi +264 -28
  126. data/spec/test_data/v5.2-no-sorbet/expected_spell_book.rbi +278 -37
  127. data/spec/test_data/v5.2-no-sorbet/expected_srb_tc_output.txt +1 -81
  128. data/spec/test_data/v5.2-no-sorbet/expected_wand.rbi +351 -102
  129. data/spec/test_data/v5.2-no-sorbet/expected_wizard.rbi +318 -72
  130. data/spec/test_data/v5.2-no-sorbet/expected_wizard_wo_spellbook.rbi +318 -72
  131. data/spec/test_data/v5.2/expected_attachment.rbi +265 -29
  132. data/spec/test_data/v5.2/expected_blob.rbi +271 -35
  133. data/spec/test_data/v5.2/expected_helpers.rbi +17 -0
  134. data/spec/test_data/v5.2/expected_internal_metadata.rbi +273 -37
  135. data/spec/test_data/v5.2/expected_potion.rbi +259 -28
  136. data/spec/test_data/v5.2/expected_schema_migration.rbi +264 -28
  137. data/spec/test_data/v5.2/expected_spell_book.rbi +278 -37
  138. data/spec/test_data/v5.2/expected_srb_tc_output.txt +1 -81
  139. data/spec/test_data/v5.2/expected_wand.rbi +351 -102
  140. data/spec/test_data/v5.2/expected_wizard.rbi +318 -72
  141. data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +318 -72
  142. data/spec/test_data/v6.0/expected_attachment.rbi +265 -29
  143. data/spec/test_data/v6.0/expected_blob.rbi +271 -35
  144. data/spec/test_data/v6.0/expected_helpers.rbi +17 -0
  145. data/spec/test_data/v6.0/expected_internal_metadata.rbi +273 -37
  146. data/spec/test_data/v6.0/expected_potion.rbi +259 -28
  147. data/spec/test_data/v6.0/expected_schema_migration.rbi +264 -28
  148. data/spec/test_data/v6.0/expected_spell_book.rbi +278 -37
  149. data/spec/test_data/v6.0/expected_srb_tc_output.txt +1 -81
  150. data/spec/test_data/v6.0/expected_wand.rbi +351 -102
  151. data/spec/test_data/v6.0/expected_wizard.rbi +318 -72
  152. data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +318 -72
  153. metadata +120 -37
  154. data/lib/sorbet-rails/rbi/activerecord.rbi +0 -207
  155. data/spec/support/v4.2/app/helpers/application_helper.rb +0 -3
  156. data/spec/support/v4.2/sorbet/rbi/gems/sorbet-runtime.rbi +0 -647
  157. data/spec/support/v4.2/sorbet/rbi/hidden-definitions/errors.txt +0 -11998
  158. data/spec/support/v4.2/sorbet/rbi/hidden-definitions/hidden.rbi +0 -27774
  159. data/spec/support/v5.0/sorbet/rbi/gems/sorbet-runtime.rbi +0 -647
  160. data/spec/support/v5.0/sorbet/rbi/hidden-definitions/errors.txt +0 -10523
  161. data/spec/support/v5.0/sorbet/rbi/hidden-definitions/hidden.rbi +0 -24969
  162. data/spec/support/v5.1/sorbet/rbi/gems/sorbet-runtime.rbi +0 -647
  163. data/spec/support/v5.1/sorbet/rbi/hidden-definitions/errors.txt +0 -10226
  164. data/spec/support/v5.1/sorbet/rbi/hidden-definitions/hidden.rbi +0 -24635
  165. data/spec/support/v5.2/.ruby-version +0 -1
  166. data/spec/support/v5.2/sorbet/rbi/gems/sorbet-runtime.rbi +0 -644
  167. data/spec/support/v5.2/sorbet/rbi/hidden-definitions/errors.txt +0 -10046
  168. data/spec/support/v5.2/sorbet/rbi/hidden-definitions/hidden.rbi +0 -24424
  169. data/spec/support/v6.0/sorbet/rbi/gems/sorbet-runtime.rbi +0 -647
  170. data/spec/support/v6.0/sorbet/rbi/hidden-definitions/errors.txt +0 -12074
  171. data/spec/support/v6.0/sorbet/rbi/hidden-definitions/hidden.rbi +0 -28231
@@ -0,0 +1,45 @@
1
+ # typed: strict
2
+ module SorbetRails::ModelUtils
3
+ extend T::Sig
4
+ extend T::Helpers
5
+
6
+ abstract!
7
+
8
+ sig { abstract.returns(T.class_of(ActiveRecord::Base)) }
9
+ def model_class; end
10
+
11
+ sig { returns(String) }
12
+ def model_class_name
13
+ "#{model_class.name}"
14
+ end
15
+
16
+ sig { returns(String) }
17
+ def model_relation_class_name
18
+ "#{model_class.name}::ActiveRecord_Relation"
19
+ end
20
+
21
+ sig { returns(String) }
22
+ def model_assoc_proxy_class_name
23
+ "#{model_class.name}::ActiveRecord_Associations_CollectionProxy"
24
+ end
25
+
26
+ sig { returns(String) }
27
+ def model_relation_shared_module_name
28
+ "#{model_class.name}::ModelRelationShared"
29
+ end
30
+
31
+ sig { params(module_name: String).returns(String) }
32
+ def model_module_name(module_name)
33
+ "#{model_class.name}::#{module_name}"
34
+ end
35
+
36
+ sig { params(method_name: T.any(String, Symbol)).returns(T::Boolean) }
37
+ def exists_instance_method?(method_name)
38
+ model_class.method_defined?(method_name)
39
+ end
40
+
41
+ sig { params(method_name: T.any(String, Symbol)).returns(T::Boolean) }
42
+ def exists_class_method?(method_name)
43
+ model_class.respond_to?(method_name)
44
+ end
45
+ end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  require "rails"
2
3
  require "sorbet-rails/custom_finder_methods"
3
4
 
@@ -1,20 +1,27 @@
1
- # typed: true
2
- class RoutesRbiFormatter
1
+ # typed: strict
2
+ class SorbetRails::RoutesRbiFormatter
3
+ extend T::Sig
4
+
5
+ sig { void }
3
6
  def initialize
4
- @buffer = []
7
+ @buffer = T.let([], T::Array[T.any(String, T::Array[String])])
5
8
  end
6
9
 
10
+ sig { params(title: String).void }
7
11
  def section_title(title)
8
12
  @buffer << "\n# Section #{title}"
9
13
  end
10
14
 
15
+ sig { params(routes: T::Array[T::Hash[Symbol, String]]).void }
11
16
  def section(routes)
12
17
  @buffer << draw_section(routes)
13
18
  end
14
19
 
20
+ sig { params(routes: T.untyped).returns(NilClass) }
15
21
  def header(routes)
16
22
  end
17
23
 
24
+ sig { params(routes: T.untyped, filter: T.untyped).void }
18
25
  def no_routes(routes=nil, filter=nil)
19
26
  @buffer <<
20
27
  <<~MESSAGE
@@ -24,6 +31,7 @@ class RoutesRbiFormatter
24
31
  MESSAGE
25
32
  end
26
33
 
34
+ sig { returns(String) }
27
35
  def result
28
36
  <<~MESSAGE
29
37
  # This is an autogenerated file for routes helper methods
@@ -38,6 +46,7 @@ class RoutesRbiFormatter
38
46
  end
39
47
 
40
48
  private
49
+ sig { params(routes: T::Array[T::Hash[Symbol, String]]).returns(T::Array[String]) }
41
50
  def draw_section(routes)
42
51
  routes.map do |r|
43
52
  if r[:name].present?
@@ -1,14 +1,17 @@
1
1
  require("sorbet-rails/model_rbi_formatter")
2
2
  require("sorbet-rails/routes_rbi_formatter")
3
+ require("sorbet-rails/helper_rbi_formatter")
3
4
  require("sorbet-rails/utils")
4
5
 
5
- # this is ugly but it's a way to get the current directory of this script
6
- # maybe someone coming along will know a better way
7
- @@sorbet_rails_rake_dir = File.dirname(__FILE__)
8
-
9
6
  namespace :rails_rbi do
7
+ desc "Generate rbis for rails models, routes, and helpers."
8
+ task :all, :environment do |t, args|
9
+ Rake::Task['rails_rbi:routes'].invoke
10
+ Rake::Task['rails_rbi:models'].invoke
11
+ Rake::Task['rails_rbi:helpers'].invoke
12
+ end
10
13
 
11
- desc "Generate rbi for rails routes"
14
+ desc "Generate rbis for rails routes"
12
15
  task :routes, [:root_dir] => :environment do |t, args|
13
16
  all_routes = Rails.application.routes.routes
14
17
  require "action_dispatch/routing/inspector"
@@ -16,15 +19,13 @@ namespace :rails_rbi do
16
19
  root_dir = args[:root_dir] || Rails.root
17
20
  file_path = Rails.root.join("sorbet", "rails-rbi", "routes.rbi")
18
21
  FileUtils.mkdir_p(File.dirname(file_path))
19
- File.write(file_path, inspector.format(RoutesRbiFormatter.new))
22
+ File.write(file_path, inspector.format(SorbetRails::RoutesRbiFormatter.new))
20
23
  end
21
24
 
22
- desc "Generate rbi for rails models. Pass models name to regenrate rbi for only the given models."
25
+ desc "Generate rbis for rails models. Pass models name to regenerate rbi for only the given models."
23
26
  task models: :environment do |t, args|
24
27
  SorbetRails::Utils.rails_eager_load_all!
25
28
 
26
- copy_bundled_rbi
27
-
28
29
  all_models = Set.new(ActiveRecord::Base.descendants + whitelisted_models - blacklisted_models)
29
30
 
30
31
  models_to_generate = args.extras.size > 0 ?
@@ -39,18 +40,31 @@ namespace :rails_rbi do
39
40
  end
40
41
  end
41
42
 
42
- def copy_bundled_rbi
43
- bundled_rbi_path = File.join(@@sorbet_rails_rake_dir, "..", "rbi", ".")
44
- copy_to_path = Rails.root.join("sorbet", "rails-rbi")
45
- FileUtils.mkdir_p(File.dirname(copy_to_path))
46
- FileUtils.cp_r(bundled_rbi_path, copy_to_path)
43
+ desc "Generate rbis for rails helpers."
44
+ task helpers: :environment do |t, args|
45
+ SorbetRails::Utils.rails_eager_load_all!
46
+
47
+ if ApplicationController.methods.include?(:modules_for_helpers)
48
+ helpers = ApplicationController.modules_for_helpers([:all])
49
+ end
50
+
51
+ # If ApplicationController doesn't work or doesn't return any helpers,
52
+ # use ActionController::Base.
53
+ if ActionController::Base.methods.include?(:modules_for_helpers) && (helpers.length == 0 || helpers.nil?)
54
+ helpers = ActionController::Base.modules_for_helpers([:all])
55
+ end
56
+
57
+ formatter = SorbetRails::HelperRbiFormatter.new(helpers)
58
+ file_path = Rails.root.join("sorbet", "rails-rbi", "helpers.rbi")
59
+ FileUtils.mkdir_p(File.dirname(file_path))
60
+ File.write(file_path, formatter.generate_rbi)
47
61
  end
48
62
 
49
63
  def generate_rbis_for_models(model_classes, available_classes)
50
64
  available_class_names = Set.new(available_classes.map { |c| c.name })
51
65
  formatted = model_classes.map do |model_class|
52
66
  begin
53
- formatter = ModelRbiFormatter.new(model_class, available_class_names)
67
+ formatter = SorbetRails::ModelRbiFormatter.new(model_class, available_class_names)
54
68
  [model_class.name, formatter.generate_rbi]
55
69
  rescue StandardError => ex
56
70
  puts "---"
@@ -64,6 +78,13 @@ namespace :rails_rbi do
64
78
  def blacklisted_models
65
79
  blacklisted_models = []
66
80
  blacklisted_models << ApplicationRecord if defined?(ApplicationRecord)
81
+ if Object.const_defined?('ActiveRecord::SchemaMigration')
82
+ # In Rails 6.0, there are dynamically created SchemaMigration classes like primary::SchemaMigration, etc.
83
+ # We ignore them because Sorbet cannot typecheck those classes and it's unlikely anyone use
84
+ # them in code.
85
+ # https://github.com/rails/rails/blob/7cc27d749c3563e6b278ad01d233cb92ea3b7935/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L170
86
+ blacklisted_models.concat(ActiveRecord::SchemaMigration.descendants)
87
+ end
67
88
  blacklisted_models
68
89
  end
69
90
 
@@ -1,5 +1,9 @@
1
+ # typed: false
1
2
 
2
3
  module SorbetRails::Utils
4
+ extend T::Sig
5
+
6
+ sig { void }
3
7
  def self.rails_eager_load_all!
4
8
  # need to eager load to see all models
5
9
  Rails.configuration.eager_load_namespaces.each { |ns| ns.try(:eager_load!) }
data/sorbet-rails.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{sorbet-rails}
3
- s.version = "0.4.0"
3
+ s.version = "0.5.0"
4
4
  s.date = %q{2019-04-18}
5
5
  s.summary = %q{Set of tools to make Sorbet work with Rails seamlessly.}
6
6
  s.authors = ["Chan Zuckerberg Initiative"]
@@ -9,12 +9,14 @@ Gem::Specification.new do |s|
9
9
  s.license = 'MIT'
10
10
  s.require_paths = ["lib"]
11
11
  s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
12
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
12
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|lib/sorbet)/}) }
13
13
  end
14
14
  s.test_files = Dir.chdir(File.expand_path('..', __FILE__)) do
15
15
  `git ls-files -z`.split("\x0").select { |f| f.match(%r{^(test|spec|features)/}) }
16
16
  end
17
17
 
18
+ s.add_dependency 'parlour', '~> 0.6.0'
19
+
18
20
  # Development
19
21
  s.add_development_dependency 'rspec', '~> 3.8', '>= 3.8'
20
22
  # Debugging
@@ -0,0 +1,13 @@
1
+ require 'rails_helper'
2
+ require 'sorbet-rails/helper_rbi_formatter'
3
+
4
+ RSpec.describe SorbetRails::HelperRbiFormatter do
5
+
6
+ it 'returns the expected rbi for a given array of helpers' do
7
+ formatter = SorbetRails::HelperRbiFormatter.new([BarHelper, BazHelper, FooHelper])
8
+ expect_match_file(
9
+ formatter.generate_rbi,
10
+ 'expected_helpers.rbi'
11
+ )
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails_helper'
2
+ require 'sorbet-rails/model_rbi_formatter'
3
+
4
+ RSpec.describe SorbetRails::ModelPlugins do
5
+ it 'can get & set plugins' do
6
+ current = SorbetRails::ModelRbiFormatter.get_plugins
7
+ expect(current).to include(
8
+ SorbetRails::ModelPlugins::ActiveRecordEnum,
9
+ SorbetRails::ModelPlugins::ActiveRecordNamedScope,
10
+ SorbetRails::ModelPlugins::ActiveRecordQuerying,
11
+ SorbetRails::ModelPlugins::ActiveRecordAttribute,
12
+ SorbetRails::ModelPlugins::ActiveRecordAssoc,
13
+ )
14
+ expect(current).to include(MythicalRbiPlugin)
15
+
16
+ SorbetRails::ModelRbiFormatter.set_plugins([MythicalRbiPlugin])
17
+ new_plugins = SorbetRails::ModelRbiFormatter.get_plugins
18
+ expect(new_plugins).to eql([MythicalRbiPlugin])
19
+
20
+ SorbetRails::ModelRbiFormatter.set_plugins(current)
21
+ end
22
+
23
+ it 'does not add 1 plugin twice' do
24
+ current = SorbetRails::ModelRbiFormatter.get_plugins
25
+ expect(current).to include(MythicalRbiPlugin)
26
+
27
+ SorbetRails::ModelRbiFormatter.register_plugin(MythicalRbiPlugin)
28
+ new_plugins = SorbetRails::ModelRbiFormatter.get_plugins
29
+ expect(new_plugins).to eql(current)
30
+ end
31
+ end
@@ -1,10 +1,10 @@
1
1
  require 'rails_helper'
2
2
  require 'sorbet-rails/model_rbi_formatter'
3
3
 
4
- RSpec.describe ModelRbiFormatter do
4
+ RSpec.describe SorbetRails::ModelRbiFormatter do
5
5
 
6
6
  it 'does not throw an error when given an abstract class' do
7
- formatter = ModelRbiFormatter.new(Potion, ['Potion'])
7
+ formatter = SorbetRails::ModelRbiFormatter.new(Potion, Set.new(['Potion']))
8
8
  expect_match_file(
9
9
  formatter.generate_rbi,
10
10
  'expected_potion.rbi',
@@ -12,7 +12,7 @@ RSpec.describe ModelRbiFormatter do
12
12
  end
13
13
 
14
14
  it 'generates correct rbi file for Wizard' do
15
- formatter = ModelRbiFormatter.new(Wizard, ['Wizard', 'Wand', 'SpellBook'])
15
+ formatter = SorbetRails::ModelRbiFormatter.new(Wizard, Set.new(['Wizard', 'Wand', 'SpellBook']))
16
16
  expect_match_file(
17
17
  formatter.generate_rbi,
18
18
  'expected_wizard.rbi',
@@ -20,7 +20,7 @@ RSpec.describe ModelRbiFormatter do
20
20
  end
21
21
 
22
22
  it 'generates strict belongs_to and generate overridden methods' do
23
- formatter = ModelRbiFormatter.new(Wand, ['Wizard', 'Wand', 'SpellBook'])
23
+ formatter = SorbetRails::ModelRbiFormatter.new(Wand, Set.new(['Wizard', 'Wand', 'SpellBook']))
24
24
  expect_match_file(
25
25
  formatter.generate_rbi,
26
26
  'expected_wand.rbi',
@@ -29,7 +29,7 @@ RSpec.describe ModelRbiFormatter do
29
29
 
30
30
  context 'there is a hidden model' do
31
31
  it 'fallbacks to use ActiveRecord::Relation' do
32
- formatter = ModelRbiFormatter.new(Wizard, ['Wizard', 'Wand'])
32
+ formatter = SorbetRails::ModelRbiFormatter.new(Wizard, Set.new(['Wizard', 'Wand']))
33
33
  expect_match_file(
34
34
  formatter.generate_rbi,
35
35
  'expected_wizard_wo_spellbook.rbi',
@@ -0,0 +1,14 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'rake rails_rbi:helpers', type: :task do
4
+ it "preloads the Rails environment" do
5
+ expect(task.prerequisites).to include("environment")
6
+ end
7
+
8
+ it "generates helpers.rbi correctly" do
9
+ task.invoke
10
+ expected_path = Rails.root.join("sorbet", "rails-rbi", "helpers.rbi")
11
+ generated = File.read(expected_path)
12
+ expect_match_file(generated, 'expected_helpers.rbi')
13
+ end
14
+ end
@@ -1,7 +1,7 @@
1
1
  require 'rails_helper'
2
2
  require 'sorbet-rails/routes_rbi_formatter'
3
3
 
4
- RSpec.describe RoutesRbiFormatter do
4
+ RSpec.describe SorbetRails::RoutesRbiFormatter do
5
5
  it 'sets up Rails Application' do
6
6
  expect(Rails.application.routes).to_not be_empty
7
7
  end
@@ -10,7 +10,7 @@ RSpec.describe RoutesRbiFormatter do
10
10
  all_routes = Rails.application.routes.routes
11
11
  require "action_dispatch/routing/inspector"
12
12
  inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
13
- formatted = inspector.format(RoutesRbiFormatter.new)
13
+ formatted = inspector.format(SorbetRails::RoutesRbiFormatter.new)
14
14
  expect_match_file(formatted, 'expected_routes.rbi')
15
15
  end
16
16
 
@@ -21,7 +21,7 @@ RSpec.describe RoutesRbiFormatter do
21
21
  end
22
22
  require "action_dispatch/routing/inspector"
23
23
  inspector = ActionDispatch::Routing::RoutesInspector.new(empty_set.routes)
24
- formatted = inspector.format(RoutesRbiFormatter.new)
24
+ formatted = inspector.format(SorbetRails::RoutesRbiFormatter.new)
25
25
  expect_match_file(formatted, 'expected_no_routes.rbi')
26
26
  end
27
27
  end
data/spec/sorbet_spec.rb CHANGED
@@ -29,29 +29,25 @@ RSpec.describe 'sorbet' do
29
29
  {'SRB_YES' => '1'}, 'bundle', 'exec', 'srb', 'init',
30
30
  chdir: Rails.root.to_path,
31
31
  )
32
- # copy test case over after initializing otherwise it'll override the `typed:` indicator
33
- res = FileUtils.symlink(
34
- Rails.root.join('..', 'rails_shared', 'sorbet_test_cases.rb'),
35
- Rails.root.to_path,
36
- force: true,
37
- )
38
32
  end
39
- end
40
33
 
41
- after(:all) do
42
- if ENV['TEST_SRB_INIT']
43
- FileUtils.safe_unlink(Rails.root.join('sorbet_test_cases.rb'))
44
- end
45
- end
34
+ # run sorbet-rails rake tasks
35
+ Rake::Task['rails_rbi:all'].invoke
46
36
 
47
- before(:each) do
48
- Rake::Task['rails_rbi:routes'].invoke
49
- Rake::Task['rails_rbi:models'].invoke
37
+ # Regenerate hidden-definitions because there might be conflicts between signature
38
+ # generated by sorbet-rails & by hidden-definitions
39
+ # They should be resolved when re-running this script
40
+ stdout, stderr, status = Open3.capture3(
41
+ 'bundle', 'exec', 'srb', 'rbi', 'hidden-definitions',
42
+ chdir: Rails.root.to_path,
43
+ )
44
+ # TODO srb rbi hidden-definitions is not working with sorbet & Rails 6.0.0.rc2
45
+ puts stderr, status
50
46
  end
51
47
 
52
48
  it 'returns expected sorbet tc result' do
53
49
  stdout, stderr, status = Open3.capture3(
54
- 'bundle', 'exec', 'srb', 'tc',
50
+ 'bundle', 'exec', 'srb', 'tc', '--typed-override=typed-override.yaml',
55
51
  chdir: Rails.root.to_path,
56
52
  )
57
53
  expect(stdout).to eql('')
@@ -1,2 +1,2 @@
1
- class ApplicationController < ActionController::API
1
+ class ApplicationController < ActionController::Base
2
2
  end
@@ -0,0 +1,2 @@
1
+ module BarHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module BazHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module FooHelper
2
+ end
@@ -0,0 +1,10 @@
1
+ require 'active_support/concern'
2
+ module Mythical
3
+ extend ActiveSupport::Concern
4
+
5
+ class_methods do
6
+ def mythicals
7
+ all.to_a # yeah!
8
+ end
9
+ end
10
+ end
@@ -1,4 +1,5 @@
1
1
  class Wand < ApplicationRecord
2
+ include Mythical
2
3
 
3
4
  enum core_type: {
4
5
  phoenix_feather: 0,
@@ -0,0 +1,3 @@
1
+ # typed: strict
2
+ require(Rails.root.join('lib/mythical_rbi_plugin'))
3
+ SorbetRails::ModelRbiFormatter.register_plugin(MythicalRbiPlugin)
@@ -0,0 +1,16 @@
1
+ # typed: true
2
+ class MythicalRbiPlugin < SorbetRails::ModelPlugins::Base
3
+ def generate(root)
4
+ return unless @model_class.include?(Mythical)
5
+
6
+ model_class_rbi = root.create_class(self.model_class_name)
7
+
8
+ # ActiveSupport::Concern class method will be inserted to the class
9
+ # directly. We need to also put the sig in the model class rbi directly
10
+ model_class_rbi.create_method(
11
+ 'mythicals',
12
+ class_method: true,
13
+ return_type: "T::Array[#{@model_class.name}]",
14
+ )
15
+ end
16
+ end