railties 7.0.8 → 7.2.0

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.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +188 -268
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.md +99 -0
  5. data/README.rdoc +4 -4
  6. data/lib/minitest/rails_plugin.rb +67 -1
  7. data/lib/rails/all.rb +1 -3
  8. data/lib/rails/api/task.rb +39 -6
  9. data/lib/rails/application/bootstrap.rb +28 -10
  10. data/lib/rails/application/configuration.rb +228 -72
  11. data/lib/rails/application/default_middleware_stack.rb +8 -2
  12. data/lib/rails/application/dummy_config.rb +19 -0
  13. data/lib/rails/application/finisher.rb +50 -33
  14. data/lib/rails/application.rb +110 -76
  15. data/lib/rails/backtrace_cleaner.rb +19 -4
  16. data/lib/rails/cli.rb +5 -3
  17. data/lib/rails/command/actions.rb +10 -12
  18. data/lib/rails/command/base.rb +55 -53
  19. data/lib/rails/command/environment_argument.rb +32 -16
  20. data/lib/rails/command/helpers/editor.rb +17 -12
  21. data/lib/rails/command.rb +84 -33
  22. data/lib/rails/commands/about/about_command.rb +14 -0
  23. data/lib/rails/commands/app/update_command.rb +93 -0
  24. data/lib/rails/commands/application/application_command.rb +2 -0
  25. data/lib/rails/commands/boot/boot_command.rb +14 -0
  26. data/lib/rails/commands/console/console_command.rb +11 -30
  27. data/lib/rails/commands/console/irb_console.rb +137 -0
  28. data/lib/rails/commands/credentials/USAGE +53 -55
  29. data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
  30. data/lib/rails/commands/credentials/credentials_command.rb +64 -70
  31. data/lib/rails/commands/db/system/change/change_command.rb +2 -1
  32. data/lib/rails/commands/dbconsole/dbconsole_command.rb +32 -131
  33. data/lib/rails/commands/destroy/destroy_command.rb +3 -2
  34. data/lib/rails/commands/dev/dev_command.rb +1 -6
  35. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  36. data/lib/rails/commands/encrypted/USAGE +15 -20
  37. data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
  38. data/lib/rails/commands/gem_help/USAGE +16 -0
  39. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  40. data/lib/rails/commands/generate/generate_command.rb +2 -2
  41. data/lib/rails/commands/help/USAGE +13 -13
  42. data/lib/rails/commands/help/help_command.rb +21 -2
  43. data/lib/rails/commands/initializers/initializers_command.rb +1 -4
  44. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  45. data/lib/rails/commands/new/new_command.rb +2 -0
  46. data/lib/rails/commands/notes/notes_command.rb +2 -1
  47. data/lib/rails/commands/plugin/plugin_command.rb +2 -0
  48. data/lib/rails/commands/rake/rake_command.rb +25 -22
  49. data/lib/rails/commands/restart/restart_command.rb +14 -0
  50. data/lib/rails/commands/routes/routes_command.rb +13 -1
  51. data/lib/rails/commands/runner/USAGE +14 -12
  52. data/lib/rails/commands/runner/runner_command.rb +42 -19
  53. data/lib/rails/commands/secret/secret_command.rb +13 -0
  54. data/lib/rails/commands/server/server_command.rb +37 -34
  55. data/lib/rails/commands/test/USAGE +14 -0
  56. data/lib/rails/commands/test/test_command.rb +58 -14
  57. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  58. data/lib/rails/commands/version/version_command.rb +1 -0
  59. data/lib/rails/configuration.rb +15 -6
  60. data/lib/rails/console/app.rb +5 -35
  61. data/lib/rails/console/helpers.rb +5 -16
  62. data/lib/rails/console/methods.rb +23 -0
  63. data/lib/rails/deprecator.rb +7 -0
  64. data/lib/rails/engine/configuration.rb +50 -6
  65. data/lib/rails/engine.rb +51 -23
  66. data/lib/rails/gem_version.rb +3 -3
  67. data/lib/rails/generators/actions.rb +6 -15
  68. data/lib/rails/generators/active_model.rb +28 -14
  69. data/lib/rails/generators/app_base.rb +382 -88
  70. data/lib/rails/generators/app_name.rb +3 -14
  71. data/lib/rails/generators/base.rb +21 -9
  72. data/lib/rails/generators/database.rb +231 -35
  73. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  74. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  75. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  76. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  77. data/lib/rails/generators/generated_attribute.rb +38 -1
  78. data/lib/rails/generators/migration.rb +4 -5
  79. data/lib/rails/generators/model_helpers.rb +2 -1
  80. data/lib/rails/generators/rails/app/USAGE +22 -6
  81. data/lib/rails/generators/rails/app/app_generator.rb +132 -82
  82. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +110 -0
  83. data/lib/rails/generators/rails/app/templates/Gemfile.tt +19 -21
  84. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  85. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
  86. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
  87. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  88. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  89. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  90. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  91. data/lib/rails/generators/rails/app/templates/bin/setup.tt +15 -2
  92. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
  93. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  94. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +11 -6
  95. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +10 -3
  96. data/lib/rails/generators/rails/app/templates/config/databases/{jdbcmysql.yml.tt → trilogy.yml.tt} +12 -7
  97. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +25 -8
  98. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +37 -28
  99. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +20 -13
  100. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
  101. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  102. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  103. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +4 -4
  104. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
  105. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  106. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  107. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +24 -34
  108. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +9 -1
  109. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  110. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +15 -0
  111. data/lib/rails/generators/rails/app/templates/dockerignore.tt +56 -0
  112. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  113. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  114. data/lib/rails/generators/rails/app/templates/gitignore.tt +7 -11
  115. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  116. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  117. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  118. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  119. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  120. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  121. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  122. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  123. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  124. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  125. data/lib/rails/generators/rails/controller/USAGE +12 -4
  126. data/lib/rails/generators/rails/controller/controller_generator.rb +6 -1
  127. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  128. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  129. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  130. data/lib/rails/generators/rails/db/system/change/change_generator.rb +146 -5
  131. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
  132. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  133. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  134. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  135. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  136. data/lib/rails/generators/rails/migration/USAGE +21 -11
  137. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  138. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  139. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  140. data/lib/rails/generators/rails/plugin/plugin_generator.rb +43 -22
  141. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  142. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +7 -3
  143. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  144. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  145. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  146. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  147. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  148. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  149. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  150. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  151. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  152. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
  153. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  154. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  155. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  156. data/lib/rails/generators/test_case.rb +2 -2
  157. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  158. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  159. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +16 -2
  160. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  161. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  162. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  163. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  164. data/lib/rails/generators/testing/assertions.rb +20 -0
  165. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +8 -4
  166. data/lib/rails/generators.rb +7 -15
  167. data/lib/rails/health_controller.rb +55 -0
  168. data/lib/rails/info.rb +3 -3
  169. data/lib/rails/info_controller.rb +31 -11
  170. data/lib/rails/mailers_controller.rb +29 -6
  171. data/lib/rails/paths.rb +15 -12
  172. data/lib/rails/pwa_controller.rb +15 -0
  173. data/lib/rails/rack/logger.rb +27 -16
  174. data/lib/rails/rackup/server.rb +15 -0
  175. data/lib/rails/railtie/configurable.rb +2 -2
  176. data/lib/rails/railtie/configuration.rb +14 -1
  177. data/lib/rails/railtie.rb +20 -21
  178. data/lib/rails/source_annotation_extractor.rb +67 -18
  179. data/lib/rails/tasks/engine.rake +8 -8
  180. data/lib/rails/tasks/framework.rake +2 -34
  181. data/lib/rails/tasks/log.rake +1 -1
  182. data/lib/rails/tasks/misc.rake +3 -14
  183. data/lib/rails/tasks/statistics.rake +5 -4
  184. data/lib/rails/tasks/tmp.rake +6 -6
  185. data/lib/rails/tasks/zeitwerk.rake +15 -35
  186. data/lib/rails/tasks.rb +0 -2
  187. data/lib/rails/templates/layouts/application.html.erb +1 -1
  188. data/lib/rails/templates/rails/mailers/email.html.erb +44 -8
  189. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  190. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  191. data/lib/rails/templates/rails/welcome/index.html.erb +5 -2
  192. data/lib/rails/test_help.rb +11 -18
  193. data/lib/rails/test_unit/line_filtering.rb +1 -1
  194. data/lib/rails/test_unit/reporter.rb +14 -4
  195. data/lib/rails/test_unit/runner.rb +62 -20
  196. data/lib/rails/test_unit/test_parser.rb +133 -0
  197. data/lib/rails/test_unit/testing.rake +13 -33
  198. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  199. data/lib/rails/version.rb +1 -1
  200. data/lib/rails/zeitwerk_checker.rb +15 -0
  201. data/lib/rails.rb +20 -17
  202. metadata +89 -42
  203. data/RDOC_MAIN.rdoc +0 -97
  204. data/lib/rails/app_updater.rb +0 -40
  205. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  206. data/lib/rails/commands/secrets/USAGE +0 -66
  207. data/lib/rails/commands/secrets/secrets_command.rb +0 -65
  208. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  209. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  210. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  211. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  212. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  213. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
  214. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  215. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  216. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  217. data/lib/rails/generators/rails/model/USAGE +0 -113
  218. data/lib/rails/ruby_version_check.rb +0 -15
  219. data/lib/rails/secrets.rb +0 -110
  220. data/lib/rails/tasks/middleware.rake +0 -9
  221. data/lib/rails/tasks/restart.rake +0 -9
@@ -5,7 +5,7 @@ require "rails/test_unit/runner"
5
5
  module Rails
6
6
  module LineFiltering # :nodoc:
7
7
  def run(reporter, options = {})
8
- options[:filter] = Rails::TestUnit::Runner.compose_filter(self, options[:filter])
8
+ options = options.merge(filter: Rails::TestUnit::Runner.compose_filter(self, options[:filter]))
9
9
 
10
10
  super
11
11
  end
@@ -6,7 +6,14 @@ require "minitest"
6
6
  module Rails
7
7
  class TestUnitReporter < Minitest::StatisticsReporter
8
8
  class_attribute :app_root
9
- class_attribute :executable, default: "rails test"
9
+ class_attribute :executable, default: "bin/rails test"
10
+
11
+ def prerecord(test_class, test_name)
12
+ super
13
+ if options[:verbose]
14
+ io.print "%s#%s = " % [test_class.name, test_name]
15
+ end
16
+ end
10
17
 
11
18
  def record(result)
12
19
  super
@@ -52,7 +59,11 @@ module Rails
52
59
  end
53
60
 
54
61
  def relative_path_for(file)
55
- file.sub(/^#{app_root}\/?/, "")
62
+ if app_root
63
+ file.sub(/^#{app_root}\/?/, "")
64
+ else
65
+ file
66
+ end
56
67
  end
57
68
 
58
69
  private
@@ -65,8 +76,7 @@ module Rails
65
76
  end
66
77
 
67
78
  def format_line(result)
68
- klass = result.respond_to?(:klass) ? result.klass : result.class
69
- "%s#%s = %.2f s = %s" % [klass, result.name, result.time, result.result_code]
79
+ "%.2f s = %s" % [result.time, result.result_code]
70
80
  end
71
81
 
72
82
  def format_rerun_snippet(result)
@@ -1,14 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "shellwords"
4
- require "method_source"
5
4
  require "rake/file_list"
6
5
  require "active_support"
7
6
  require "active_support/core_ext/module/attribute_accessors"
7
+ require "active_support/core_ext/range"
8
+ require "rails/test_unit/test_parser"
8
9
 
9
10
  module Rails
10
11
  module TestUnit
12
+ class InvalidTestError < StandardError
13
+ def initialize(path, suggestion)
14
+ super(<<~MESSAGE.squish)
15
+ Could not load test file: #{path}.
16
+ #{suggestion}
17
+ MESSAGE
18
+ end
19
+ end
20
+
11
21
  class Runner
22
+ TEST_FOLDERS = [:models, :helpers, :channels, :controllers, :mailers, :integration, :jobs, :mailboxes]
23
+ PATH_ARGUMENT_PATTERN = %r"^(?!/.+/$)[.\w]*[/\\]"
12
24
  mattr_reader :filters, default: []
13
25
 
14
26
  class << self
@@ -30,9 +42,9 @@ module Rails
30
42
  $VERBOSE = argv.delete_at(w_index) if w_index
31
43
  end
32
44
 
33
- def rake_run(argv = [])
45
+ def run_from_rake(test_command, argv = [])
34
46
  # Ensure the tests run during the Rake Task action, not when the process exits
35
- success = system("rails", "test", *argv, *Shellwords.split(ENV["TESTOPTS"] || ""))
47
+ success = system("rails", test_command, *argv, *Shellwords.split(ENV["TESTOPTS"] || ""))
36
48
  success || exit(false)
37
49
  end
38
50
 
@@ -43,11 +55,29 @@ module Rails
43
55
  end
44
56
 
45
57
  def load_tests(argv)
46
- tests = list_tests(argv)
47
- tests.to_a.each { |path| require File.expand_path(path) }
58
+ patterns = extract_filters(argv)
59
+ tests = list_tests(patterns)
60
+ tests.to_a.each do |path|
61
+ abs_path = File.expand_path(path)
62
+ require abs_path
63
+ rescue LoadError => exception
64
+ if exception.path == abs_path
65
+ all_tests = list_tests([default_test_glob])
66
+ corrections = DidYouMean::SpellChecker.new(dictionary: all_tests).correct(path)
67
+
68
+ if corrections.empty?
69
+ raise exception
70
+ end
71
+ raise InvalidTestError.new(path, DidYouMean::Formatter.message_for(corrections))
72
+ else
73
+ raise
74
+ end
75
+ end
48
76
  end
49
77
 
50
78
  def compose_filter(runnable, filter)
79
+ filter = normalize_declarative_test_filter(filter)
80
+
51
81
  if filters.any? { |_, lines| lines.any? }
52
82
  CompositeFilter.new(runnable, filter, filters)
53
83
  else
@@ -59,11 +89,11 @@ module Rails
59
89
  def extract_filters(argv)
60
90
  # Extract absolute and relative paths but skip -n /.*/ regexp filters.
61
91
  argv.filter_map do |path|
62
- next unless path_argument?(path) && !regexp_filter?(path)
92
+ next unless path_argument?(path)
63
93
 
64
94
  path = path.tr("\\", "/")
65
95
  case
66
- when /(:\d+)+$/.match?(path)
96
+ when /(:\d+(-\d+)?)+$/.match?(path)
67
97
  file, *lines = path.split(":")
68
98
  filters << [ file, lines ]
69
99
  file
@@ -81,7 +111,7 @@ module Rails
81
111
  end
82
112
 
83
113
  def default_test_exclude_glob
84
- ENV["DEFAULT_TEST_EXCLUDE"] || "test/{system,dummy}/**/*_test.rb"
114
+ ENV["DEFAULT_TEST_EXCLUDE"] || "test/{system,dummy,fixtures}/**/*_test.rb"
85
115
  end
86
116
 
87
117
  def regexp_filter?(arg)
@@ -89,16 +119,27 @@ module Rails
89
119
  end
90
120
 
91
121
  def path_argument?(arg)
92
- %r"^[/\\]?\w+[/\\]".match?(arg)
122
+ PATH_ARGUMENT_PATTERN.match?(arg)
93
123
  end
94
124
 
95
- def list_tests(argv)
96
- patterns = extract_filters(argv)
97
-
125
+ def list_tests(patterns)
98
126
  tests = Rake::FileList[patterns.any? ? patterns : default_test_glob]
99
127
  tests.exclude(default_test_exclude_glob) if patterns.empty?
100
128
  tests
101
129
  end
130
+
131
+ def normalize_declarative_test_filter(filter)
132
+ if filter.is_a?(String)
133
+ if regexp_filter?(filter)
134
+ # Minitest::Spec::DSL#it does not replace whitespace in method
135
+ # names, so match unmodified method names as well.
136
+ filter = filter.gsub(/\s+/, "_").delete_suffix("/") + "|" + filter.delete_prefix("/")
137
+ elsif !filter.start_with?("test_")
138
+ filter = "test_#{filter.gsub(/\s+/, "_")}"
139
+ end
140
+ end
141
+ filter
142
+ end
102
143
  end
103
144
  end
104
145
 
@@ -139,17 +180,21 @@ module Rails
139
180
  end
140
181
 
141
182
  class Filter # :nodoc:
142
- def initialize(runnable, file, line)
183
+ def initialize(runnable, file, line_or_range)
143
184
  @runnable, @file = runnable, File.expand_path(file)
144
- @line = line.to_i if line
185
+ if line_or_range
186
+ first, last = line_or_range.split("-").map(&:to_i)
187
+ last ||= first
188
+ @line_range = Range.new(first, last)
189
+ end
145
190
  end
146
191
 
147
192
  def ===(method)
148
193
  return unless @runnable.method_defined?(method)
149
194
 
150
- if @line
195
+ if @line_range
151
196
  test_file, test_range = definition_for(@runnable.instance_method(method))
152
- test_file == @file && test_range.include?(@line)
197
+ test_file == @file && @line_range.overlaps?(test_range)
153
198
  else
154
199
  @runnable.instance_method(method).source_location.first == @file
155
200
  end
@@ -157,10 +202,7 @@ module Rails
157
202
 
158
203
  private
159
204
  def definition_for(method)
160
- file, start_line = method.source_location
161
- end_line = method.source.count("\n") + start_line - 1
162
-
163
- return file, start_line..end_line
205
+ TestParser.definition_for(method)
164
206
  end
165
207
  end
166
208
  end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "prism"
5
+ rescue LoadError
6
+ # If Prism isn't available (because of using an older Ruby version) then we'll
7
+ # define a fallback parser using ripper.
8
+ end
9
+
10
+ if defined?(Prism)
11
+ module Rails
12
+ module TestUnit
13
+ # Parse a test file to extract the line ranges of all tests in both
14
+ # method-style (def test_foo) and declarative-style (test "foo" do)
15
+ module TestParser
16
+ # Helper to translate a method object into the path and line range where
17
+ # the method was defined.
18
+ def self.definition_for(method)
19
+ filepath, start_line = method.source_location
20
+ queue = [Prism.parse_file(filepath).value]
21
+
22
+ while (node = queue.shift)
23
+ case node.type
24
+ when :def_node
25
+ if node.location.start_line == start_line
26
+ return [filepath, start_line..node.location.end_line]
27
+ end
28
+ when :call_node
29
+ if node.location.start_line == start_line
30
+ return [filepath, start_line..node.location.end_line]
31
+ end
32
+ end
33
+
34
+ queue.concat(node.compact_child_nodes)
35
+ end
36
+
37
+ nil
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ # If we have Prism, then we don't need to define the fallback parser using
44
+ # ripper.
45
+ return
46
+ end
47
+
48
+ require "ripper"
49
+
50
+ module Rails
51
+ module TestUnit
52
+ # Parse a test file to extract the line ranges of all tests in both
53
+ # method-style (def test_foo) and declarative-style (test "foo" do)
54
+ class TestParser < Ripper # :nodoc:
55
+ # Helper to translate a method object into the path and line range where
56
+ # the method was defined.
57
+ def self.definition_for(method_obj)
58
+ path, begin_line = method_obj.source_location
59
+ begins_to_ends = new(File.read(path), path).parse
60
+ return unless end_line = begins_to_ends[begin_line]
61
+ [path, (begin_line..end_line)]
62
+ end
63
+
64
+ def initialize(*)
65
+ # A hash mapping the 1-indexed line numbers that tests start on to where they end.
66
+ @begins_to_ends = {}
67
+ super
68
+ end
69
+
70
+ def parse
71
+ super
72
+ @begins_to_ends
73
+ end
74
+
75
+ # method test e.g. `def test_some_description`
76
+ # This event's first argument gets the `ident` node containing the method
77
+ # name, which we have overridden to return the line number of the ident
78
+ # instead.
79
+ def on_def(begin_line, *)
80
+ @begins_to_ends[begin_line] = lineno
81
+ end
82
+
83
+ # Everything past this point is to support declarative tests, which
84
+ # require more work to get right because of the many different ways
85
+ # methods can be invoked in ruby, all of which are parsed differently.
86
+ #
87
+ # The approach is just to store the current line number when the
88
+ # "test" method is called and pass it up the tree so it's available at
89
+ # the point when we also know the line where the associated block ends.
90
+
91
+ def on_method_add_block(begin_line, end_line)
92
+ if begin_line && end_line
93
+ @begins_to_ends[begin_line] = end_line
94
+ end
95
+ end
96
+
97
+ def on_command_call(*, begin_lineno, _args)
98
+ begin_lineno
99
+ end
100
+
101
+ def first_arg(arg, *)
102
+ arg
103
+ end
104
+
105
+ def just_lineno(*)
106
+ lineno
107
+ end
108
+
109
+ alias on_method_add_arg first_arg
110
+ alias on_command first_arg
111
+ alias on_stmts_add first_arg
112
+ alias on_arg_paren first_arg
113
+ alias on_bodystmt first_arg
114
+
115
+ alias on_ident just_lineno
116
+ alias on_do_block just_lineno
117
+ alias on_stmts_new just_lineno
118
+ alias on_brace_block just_lineno
119
+
120
+ def on_args_new
121
+ []
122
+ end
123
+
124
+ def on_args_add(parts, part)
125
+ parts << part
126
+ end
127
+
128
+ def on_args_add_block(args, *rest)
129
+ args.first
130
+ end
131
+ end
132
+ end
133
+ end
@@ -1,18 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "minitest"
4
3
  require "minitest"
5
4
  require "rails/test_unit/runner"
6
5
 
7
6
  task default: :test
8
7
 
9
- desc "Runs all tests in test folder except system ones"
8
+ desc "Run all tests in test folder except system ones"
10
9
  task :test do
11
- if ENV.key?("TEST")
12
- Rails::TestUnit::Runner.rake_run([ENV["TEST"]])
13
- else
14
- Rails::TestUnit::Runner.rake_run
15
- end
10
+ Rails::TestUnit::Runner.run_from_rake("test", Array(ENV["TEST"]))
16
11
  end
17
12
 
18
13
  namespace :test do
@@ -23,37 +18,22 @@ namespace :test do
23
18
 
24
19
  task run: %w[test]
25
20
 
26
- desc "Run tests quickly, but also reset db"
21
+ desc "Reset the database and run `bin/rails test`"
27
22
  task :db do
28
23
  success = system({ "RAILS_ENV" => ENV.fetch("RAILS_ENV", "test") }, "rake", "db:test:prepare", "test")
29
24
  success || exit(false)
30
25
  end
31
26
 
32
- ["models", "helpers", "channels", "controllers", "mailers", "integration", "jobs", "mailboxes"].each do |name|
33
- task name => "test:prepare" do
34
- Rails::TestUnit::Runner.rake_run(["test/#{name}"])
27
+ [
28
+ *Rails::TestUnit::Runner::TEST_FOLDERS,
29
+ :all,
30
+ :generators,
31
+ :units,
32
+ :functionals,
33
+ :system,
34
+ ].each do |name|
35
+ task name do
36
+ Rails::TestUnit::Runner.run_from_rake("test:#{name}")
35
37
  end
36
38
  end
37
-
38
- desc "Runs all tests, including system tests"
39
- task all: "test:prepare" do
40
- Rails::TestUnit::Runner.rake_run(["test/**/*_test.rb"])
41
- end
42
-
43
- task generators: "test:prepare" do
44
- Rails::TestUnit::Runner.rake_run(["test/lib/generators"])
45
- end
46
-
47
- task units: "test:prepare" do
48
- Rails::TestUnit::Runner.rake_run(["test/models", "test/helpers", "test/unit"])
49
- end
50
-
51
- task functionals: "test:prepare" do
52
- Rails::TestUnit::Runner.rake_run(["test/controllers", "test/mailers", "test/functional"])
53
- end
54
-
55
- desc "Run system tests only"
56
- task system: "test:prepare" do
57
- Rails::TestUnit::Runner.rake_run(["test/system"])
58
- end
59
39
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(ActiveRecord::Base)
4
+ begin
5
+ ActiveRecord::Migration.maintain_test_schema!
6
+ rescue ActiveRecord::PendingMigrationError => e
7
+ puts e.to_s.strip
8
+ exit 1
9
+ end
10
+
11
+ if Rails.configuration.eager_load
12
+ ActiveRecord::Base.descendants.each do |model|
13
+ model.load_schema if !model.abstract_class? && model.table_exists?
14
+ end
15
+ end
16
+ end
data/lib/rails/version.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module Rails
6
- # Returns the currently loaded version of Rails as a string.
6
+ # Returns the currently loaded version of \Rails as a string.
7
7
  def self.version
8
8
  VERSION::STRING
9
9
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The actual (private) implementation of the Rake task zeitwerk:check.
4
+ class Rails::ZeitwerkChecker # :nodoc:
5
+ def self.check
6
+ Zeitwerk::Loader.eager_load_all
7
+
8
+ autoloaded = ActiveSupport::Dependencies.autoload_paths + ActiveSupport::Dependencies.autoload_once_paths
9
+ eager_loaded = ActiveSupport::Dependencies._eager_load_paths.to_a
10
+
11
+ unchecked = autoloaded - eager_loaded
12
+ unchecked.select! { |dir| Dir.exist?(dir) && !Dir.empty?(dir) }
13
+ unchecked
14
+ end
15
+ end
data/lib/rails.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rails/ruby_version_check"
4
-
5
3
  require "pathname"
6
4
 
7
5
  require "active_support"
@@ -10,8 +8,10 @@ require "active_support/core_ext/module/delegation"
10
8
  require "active_support/core_ext/array/extract_options"
11
9
  require "active_support/core_ext/object/blank"
12
10
 
13
- require "rails/application"
14
11
  require "rails/version"
12
+ require "rails/deprecator"
13
+ require "rails/application"
14
+ require "rails/backtrace_cleaner"
15
15
 
16
16
  require "active_support/railtie"
17
17
  require "action_dispatch/railtie"
@@ -22,6 +22,7 @@ silence_warnings do
22
22
  Encoding.default_internal = Encoding::UTF_8
23
23
  end
24
24
 
25
+ # :include: ../README.rdoc
25
26
  module Rails
26
27
  extend ActiveSupport::Autoload
27
28
  extend ActiveSupport::Benchmarkable
@@ -31,6 +32,11 @@ module Rails
31
32
  autoload :MailersController
32
33
  autoload :WelcomeController
33
34
 
35
+ eager_autoload do
36
+ autoload :HealthController
37
+ autoload :PwaController
38
+ end
39
+
34
40
  class << self
35
41
  @application = @app_class = nil
36
42
 
@@ -42,20 +48,16 @@ module Rails
42
48
 
43
49
  delegate :initialize!, :initialized?, to: :application
44
50
 
45
- # The Configuration instance used to configure the Rails environment
51
+ # The Configuration instance used to configure the \Rails environment
46
52
  def configuration
47
53
  application.config
48
54
  end
49
55
 
50
56
  def backtrace_cleaner
51
- @backtrace_cleaner ||= begin
52
- # Relies on Active Support, so we have to lazy load to postpone definition until Active Support has been loaded
53
- require "rails/backtrace_cleaner"
54
- Rails::BacktraceCleaner.new
55
- end
57
+ @backtrace_cleaner ||= Rails::BacktraceCleaner.new
56
58
  end
57
59
 
58
- # Returns a Pathname object of the current Rails project,
60
+ # Returns a Pathname object of the current \Rails project,
59
61
  # otherwise it returns +nil+ if there is no project:
60
62
  #
61
63
  # Rails.root
@@ -64,23 +66,24 @@ module Rails
64
66
  application && application.config.root
65
67
  end
66
68
 
67
- # Returns the current Rails environment.
69
+ # Returns the current \Rails environment.
68
70
  #
69
71
  # Rails.env # => "development"
70
72
  # Rails.env.development? # => true
71
73
  # Rails.env.production? # => false
74
+ # Rails.env.local? # => true true for "development" and "test", false for anything else
72
75
  def env
73
76
  @_env ||= ActiveSupport::EnvironmentInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development")
74
77
  end
75
78
 
76
- # Sets the Rails environment.
79
+ # Sets the \Rails environment.
77
80
  #
78
81
  # Rails.env = "staging" # => "staging"
79
82
  def env=(environment)
80
83
  @_env = ActiveSupport::EnvironmentInquirer.new(environment)
81
84
  end
82
85
 
83
- # Returns the ActiveSupport::ErrorReporter of the current Rails project,
86
+ # Returns the ActiveSupport::ErrorReporter of the current \Rails project,
84
87
  # otherwise it returns +nil+ if there is no project.
85
88
  #
86
89
  # Rails.error.handle(IOError) do
@@ -88,12 +91,12 @@ module Rails
88
91
  # end
89
92
  # Rails.error.report(error)
90
93
  def error
91
- application && application.executor.error_reporter
94
+ ActiveSupport.error_reporter
92
95
  end
93
96
 
94
- # Returns all Rails groups for loading based on:
97
+ # Returns all \Rails groups for loading based on:
95
98
  #
96
- # * The Rails environment;
99
+ # * The \Rails environment;
97
100
  # * The environment variable RAILS_GROUPS;
98
101
  # * The optional envs given as argument and the hash with group dependencies;
99
102
  #
@@ -112,7 +115,7 @@ module Rails
112
115
  end
113
116
 
114
117
  # Returns a Pathname object of the public folder of the current
115
- # Rails project, otherwise it returns +nil+ if there is no project:
118
+ # \Rails project, otherwise it returns +nil+ if there is no project:
116
119
  #
117
120
  # Rails.public_path
118
121
  # # => #<Pathname:/Users/someuser/some/path/project/public>