railties 7.2.3 → 8.0.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +111 -324
- data/README.rdoc +1 -1
- data/lib/minitest/rails_plugin.rb +2 -2
- data/lib/rails/application/bootstrap.rb +3 -1
- data/lib/rails/application/configuration.rb +22 -7
- data/lib/rails/application/default_middleware_stack.rb +4 -0
- data/lib/rails/application/finisher.rb +2 -2
- data/lib/rails/application/routes_reloader.rb +11 -1
- data/lib/rails/application.rb +14 -12
- data/lib/rails/backtrace_cleaner.rb +1 -1
- data/lib/rails/code_statistics.rb +128 -86
- data/lib/rails/code_statistics_calculator.rb +78 -76
- data/lib/rails/command/helpers/editor.rb +1 -1
- data/lib/rails/commands/app/update_command.rb +1 -9
- data/lib/rails/commands/console/irb_console.rb +6 -3
- data/lib/rails/commands/credentials/USAGE +4 -4
- data/lib/rails/commands/credentials/credentials_command.rb +5 -1
- data/lib/rails/commands/dev/dev_command.rb +1 -1
- data/lib/rails/commands/devcontainer/devcontainer_command.rb +1 -1
- data/lib/rails/commands/stats/stats_command.rb +19 -0
- data/lib/rails/commands/test/test_command.rb +2 -0
- data/lib/rails/dev_caching.rb +2 -2
- data/lib/rails/engine/configuration.rb +3 -1
- data/lib/rails/engine/lazy_route_set.rb +109 -0
- data/lib/rails/engine.rb +8 -3
- data/lib/rails/gem_version.rb +4 -4
- data/lib/rails/generators/actions.rb +5 -9
- data/lib/rails/generators/app_base.rb +49 -31
- data/lib/rails/generators/database.rb +101 -67
- data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
- data/lib/rails/generators/erb/authentication/templates/views/passwords/edit.html.erb +9 -0
- data/lib/rails/generators/erb/authentication/templates/views/passwords/new.html.erb +8 -0
- data/lib/rails/generators/erb/authentication/templates/views/sessions/new.html.erb +11 -0
- data/lib/rails/generators/generated_attribute.rb +16 -11
- data/lib/rails/generators/rails/app/app_generator.rb +19 -28
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +12 -3
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +23 -8
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +10 -3
- data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +5 -7
- data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +23 -0
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +23 -0
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +40 -0
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +23 -0
- data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +124 -0
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -23
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +31 -51
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -19
- data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
- data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +25 -0
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -2
- data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -3
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +4 -3
- data/lib/rails/generators/rails/app/templates/dockerignore.tt +1 -2
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +1 -3
- data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -2
- data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
- data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
- data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
- data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +113 -65
- data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
- data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
- data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/icon.svg +2 -2
- data/lib/rails/generators/rails/authentication/USAGE +6 -0
- data/lib/rails/generators/rails/authentication/authentication_generator.rb +54 -0
- data/lib/rails/generators/rails/authentication/templates/controllers/concerns/authentication.rb +55 -0
- data/lib/rails/generators/rails/authentication/templates/controllers/passwords_controller.rb +33 -0
- data/lib/rails/generators/rails/authentication/templates/controllers/sessions_controller.rb +21 -0
- data/lib/rails/generators/rails/authentication/templates/mailers/passwords_mailer.rb +6 -0
- data/lib/rails/generators/rails/authentication/templates/models/current.rb +4 -0
- data/lib/rails/generators/rails/authentication/templates/models/session.rb +3 -0
- data/lib/rails/generators/rails/authentication/templates/models/user.rb +6 -0
- data/lib/rails/generators/rails/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb +7 -0
- data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.html.erb +4 -0
- data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.text.erb +2 -0
- data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
- data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
- data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +4 -2
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +1 -1
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -9
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +2 -3
- data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +4 -4
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +5 -5
- data/lib/rails/generators/rails/script/USAGE +18 -0
- data/lib/rails/generators/rails/script/script_generator.rb +18 -0
- data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
- data/lib/rails/generators.rb +6 -5
- data/lib/rails/info_controller.rb +10 -4
- data/lib/rails/rack/silence_request.rb +33 -0
- data/lib/rails/rack.rb +1 -0
- data/lib/rails/source_annotation_extractor.rb +31 -14
- data/lib/rails/tasks/statistics.rake +13 -28
- data/lib/rails/templates/rails/info/notes.html.erb +65 -0
- data/lib/rails/test_unit/runner.rb +3 -7
- data/lib/rails/test_unit/test_parser.rb +15 -18
- metadata +45 -50
- data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
- data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
- data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +0 -70
- data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
- data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
- data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
- data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
- data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +0 -17
|
@@ -122,9 +122,12 @@ module Rails
|
|
|
122
122
|
def generate_test_dummy(force = false)
|
|
123
123
|
opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
|
|
124
124
|
opts[:force] = force
|
|
125
|
+
opts[:skip_thruster] = true
|
|
125
126
|
opts[:skip_brakeman] = true
|
|
126
127
|
opts[:skip_bundle] = true
|
|
127
128
|
opts[:skip_ci] = true
|
|
129
|
+
opts[:skip_kamal] = true
|
|
130
|
+
opts[:skip_solid] = true
|
|
128
131
|
opts[:skip_git] = true
|
|
129
132
|
opts[:skip_hotwire] = true
|
|
130
133
|
opts[:skip_rubocop] = true
|
|
@@ -149,9 +152,8 @@ module Rails
|
|
|
149
152
|
end
|
|
150
153
|
end
|
|
151
154
|
|
|
152
|
-
def
|
|
153
|
-
template "rails/stylesheets.css",
|
|
154
|
-
template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
|
|
155
|
+
def test_dummy_assets
|
|
156
|
+
template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
|
|
155
157
|
end
|
|
156
158
|
|
|
157
159
|
def test_dummy_clean
|
|
@@ -159,7 +161,7 @@ module Rails
|
|
|
159
161
|
remove_file ".ruby-version"
|
|
160
162
|
remove_dir "db"
|
|
161
163
|
remove_file "Gemfile"
|
|
162
|
-
|
|
164
|
+
remove_dir "lib"
|
|
163
165
|
remove_file "public/robots.txt"
|
|
164
166
|
remove_file "README.md"
|
|
165
167
|
remove_file "test"
|
|
@@ -167,10 +169,6 @@ module Rails
|
|
|
167
169
|
end
|
|
168
170
|
end
|
|
169
171
|
|
|
170
|
-
def assets_manifest
|
|
171
|
-
template "rails/engine_manifest.js", "app/assets/config/#{underscored_name}_manifest.js"
|
|
172
|
-
end
|
|
173
|
-
|
|
174
172
|
def stylesheets
|
|
175
173
|
if mountable?
|
|
176
174
|
copy_file "rails/stylesheets.css",
|
|
@@ -361,7 +359,7 @@ module Rails
|
|
|
361
359
|
mute do
|
|
362
360
|
build(:generate_test_dummy)
|
|
363
361
|
build(:test_dummy_config)
|
|
364
|
-
build(:
|
|
362
|
+
build(:test_dummy_assets) unless skip_asset_pipeline?
|
|
365
363
|
build(:test_dummy_clean)
|
|
366
364
|
# ensure that bin/rails has proper dummy_path
|
|
367
365
|
build(:bin)
|
|
@@ -84,10 +84,8 @@ jobs:
|
|
|
84
84
|
- name: Run tests
|
|
85
85
|
env:
|
|
86
86
|
RAILS_ENV: test
|
|
87
|
-
<%- if options[:database] == "mysql" -%>
|
|
87
|
+
<%- if options[:database] == "mysql" || options[:database] == "trilogy" -%>
|
|
88
88
|
DATABASE_URL: mysql2://127.0.0.1:3306
|
|
89
|
-
<%- elsif options[:database] == "trilogy" -%>
|
|
90
|
-
DATABASE_URL: trilogy://127.0.0.1:3306
|
|
91
89
|
<%- elsif options[:database] == "postgresql" -%>
|
|
92
90
|
DATABASE_URL: postgres://postgres:postgres@localhost:5432
|
|
93
91
|
<%- end -%>
|
|
@@ -102,3 +100,4 @@ jobs:
|
|
|
102
100
|
path: ${{ github.workspace }}/tmp/screenshots
|
|
103
101
|
if-no-files-found: ignore
|
|
104
102
|
<% end -%>
|
|
103
|
+
|
|
@@ -21,7 +21,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
21
21
|
if @<%= orm_instance.save %>
|
|
22
22
|
render json: <%= "@#{singular_table_name}" %>, status: :created, location: <%= "@#{singular_table_name}" %>
|
|
23
23
|
else
|
|
24
|
-
render json: <%= "@#{orm_instance.errors}" %>, status:
|
|
24
|
+
render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
30
30
|
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
|
31
31
|
render json: <%= "@#{singular_table_name}" %>
|
|
32
32
|
else
|
|
33
|
-
render json: <%= "@#{orm_instance.errors}" %>, status:
|
|
33
|
+
render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -42,7 +42,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
42
42
|
private
|
|
43
43
|
# Use callbacks to share common setup or constraints between actions.
|
|
44
44
|
def set_<%= singular_table_name %>
|
|
45
|
-
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params
|
|
45
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Only allow a list of trusted parameters through.
|
|
@@ -50,7 +50,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
50
50
|
<%- if attributes_names.empty? -%>
|
|
51
51
|
params.fetch(:<%= singular_table_name %>, {})
|
|
52
52
|
<%- else -%>
|
|
53
|
-
params.
|
|
53
|
+
params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
|
|
54
54
|
<%- end -%>
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -27,7 +27,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
27
27
|
if @<%= orm_instance.save %>
|
|
28
28
|
redirect_to <%= redirect_resource_name %>, notice: <%= %("#{human_name} was successfully created.") %>
|
|
29
29
|
else
|
|
30
|
-
render :new, status:
|
|
30
|
+
render :new, status: :unprocessable_entity
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -36,20 +36,20 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
36
36
|
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
|
37
37
|
redirect_to <%= redirect_resource_name %>, notice: <%= %("#{human_name} was successfully updated.") %>, status: :see_other
|
|
38
38
|
else
|
|
39
|
-
render :edit, status:
|
|
39
|
+
render :edit, status: :unprocessable_entity
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# DELETE <%= route_url %>/1
|
|
44
44
|
def destroy
|
|
45
45
|
@<%= orm_instance.destroy %>
|
|
46
|
-
redirect_to <%= index_helper %>
|
|
46
|
+
redirect_to <%= index_helper %>_path, notice: <%= %("#{human_name} was successfully destroyed.") %>, status: :see_other
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
private
|
|
50
50
|
# Use callbacks to share common setup or constraints between actions.
|
|
51
51
|
def set_<%= singular_table_name %>
|
|
52
|
-
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params
|
|
52
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
# Only allow a list of trusted parameters through.
|
|
@@ -57,7 +57,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
57
57
|
<%- if attributes_names.empty? -%>
|
|
58
58
|
params.fetch(:<%= singular_table_name %>, {})
|
|
59
59
|
<%- else -%>
|
|
60
|
-
params.
|
|
60
|
+
params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
|
|
61
61
|
<%- end -%>
|
|
62
62
|
end
|
|
63
63
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generate a one-off or general purpose script, such as a data migration
|
|
3
|
+
script, cleanup script, etc.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
`bin/rails generate script my_script`
|
|
7
|
+
|
|
8
|
+
This will create:
|
|
9
|
+
script/my_script.rb
|
|
10
|
+
|
|
11
|
+
You can run the script using:
|
|
12
|
+
`ruby script/my_script.rb`
|
|
13
|
+
|
|
14
|
+
You can specify a folder:
|
|
15
|
+
`bin/rails generate script cleanup/my_script`
|
|
16
|
+
|
|
17
|
+
This will create:
|
|
18
|
+
script/cleanup/my_script.rb
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/named_base"
|
|
4
|
+
|
|
5
|
+
module Rails
|
|
6
|
+
module Generators
|
|
7
|
+
class ScriptGenerator < NamedBase
|
|
8
|
+
def generate_script
|
|
9
|
+
template("script.rb.tt", "script/#{file_path}.rb")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
def depth
|
|
14
|
+
class_path.size + 1
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/rails/generators.rb
CHANGED
|
@@ -97,11 +97,11 @@ module Rails
|
|
|
97
97
|
# generator group to fall back to another group in case of missing generators,
|
|
98
98
|
# they can add a fallback.
|
|
99
99
|
#
|
|
100
|
-
# For example, shoulda is considered a
|
|
101
|
-
# of
|
|
102
|
-
#
|
|
100
|
+
# For example, shoulda is considered a test_framework and is an extension
|
|
101
|
+
# of test_unit. However, most part of shoulda generators are similar to
|
|
102
|
+
# test_unit ones.
|
|
103
103
|
#
|
|
104
|
-
# Shoulda then can tell generators to search for
|
|
104
|
+
# Shoulda then can tell generators to search for test_unit generators when
|
|
105
105
|
# some of them are not available by adding a fallback:
|
|
106
106
|
#
|
|
107
107
|
# Rails::Generators.fallbacks[:shoulda] = :test_unit
|
|
@@ -272,6 +272,7 @@ module Rails
|
|
|
272
272
|
#{error.detailed_message}
|
|
273
273
|
Run `bin/rails generate --help` for more options.
|
|
274
274
|
MSG
|
|
275
|
+
exit 1
|
|
275
276
|
end
|
|
276
277
|
end
|
|
277
278
|
|
|
@@ -316,7 +317,7 @@ module Rails
|
|
|
316
317
|
|
|
317
318
|
def run_after_generate_callback
|
|
318
319
|
if defined?(@@generated_files) && !@@generated_files.empty?
|
|
319
|
-
after_generate_callbacks.each do |callback|
|
|
320
|
+
@after_generate_callbacks.each do |callback|
|
|
320
321
|
callback.call(@@generated_files)
|
|
321
322
|
end
|
|
322
323
|
@@generated_files = []
|
|
@@ -7,8 +7,6 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
|
|
|
7
7
|
prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATHS
|
|
8
8
|
layout -> { request.xhr? ? false : "application" }
|
|
9
9
|
|
|
10
|
-
RFC2396_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new
|
|
11
|
-
|
|
12
10
|
before_action :require_local!
|
|
13
11
|
|
|
14
12
|
def index
|
|
@@ -22,7 +20,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
|
|
|
22
20
|
|
|
23
21
|
def routes
|
|
24
22
|
if query = params[:query]
|
|
25
|
-
query = RFC2396_PARSER.escape query
|
|
23
|
+
query = URI::RFC2396_PARSER.escape query
|
|
26
24
|
|
|
27
25
|
render json: {
|
|
28
26
|
exact: matching_routes(query: query, exact_match: true),
|
|
@@ -34,6 +32,14 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
|
|
|
34
32
|
end
|
|
35
33
|
end
|
|
36
34
|
|
|
35
|
+
def notes
|
|
36
|
+
@annotations = Rails::SourceAnnotationExtractor.new(
|
|
37
|
+
Rails::SourceAnnotationExtractor::Annotation.tags.join("|")
|
|
38
|
+
).find(
|
|
39
|
+
Rails::SourceAnnotationExtractor::Annotation.directories
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
37
43
|
private
|
|
38
44
|
def matching_routes(query:, exact_match:)
|
|
39
45
|
return [] if query.blank?
|
|
@@ -55,7 +61,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
|
|
|
55
61
|
match ||= (query === route_wrapper.verb)
|
|
56
62
|
|
|
57
63
|
unless match
|
|
58
|
-
controller_action = RFC2396_PARSER.escape(route_wrapper.reqs)
|
|
64
|
+
controller_action = URI::RFC2396_PARSER.escape(route_wrapper.reqs)
|
|
59
65
|
match = exact_match ? (query === controller_action) : controller_action.include?(query)
|
|
60
66
|
end
|
|
61
67
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
require "active_support/logger_silence"
|
|
6
|
+
|
|
7
|
+
module Rails
|
|
8
|
+
module Rack
|
|
9
|
+
# Allows you to silence requests made to a specific path.
|
|
10
|
+
# This is useful for preventing recurring requests like health checks from clogging the logging.
|
|
11
|
+
# This middleware is used to do just that against the path /up in production by default.
|
|
12
|
+
#
|
|
13
|
+
# Example:
|
|
14
|
+
#
|
|
15
|
+
# config.middleware.insert_before \
|
|
16
|
+
# Rails::Rack::Logger, Rails::Rack::SilenceRequest, path: "/up"
|
|
17
|
+
#
|
|
18
|
+
# This middleware can also be configured using `config.silence_healthcheck_path = "/up"` in Rails.
|
|
19
|
+
class SilenceRequest
|
|
20
|
+
def initialize(app, path:)
|
|
21
|
+
@app, @path = app, path
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def call(env)
|
|
25
|
+
if env["PATH_INFO"] == @path
|
|
26
|
+
Rails.logger.silence { @app.call(env) }
|
|
27
|
+
else
|
|
28
|
+
@app.call(env)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/rails/rack.rb
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
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 for the ParserExtractor using ripper.
|
|
8
|
+
require "ripper"
|
|
9
|
+
end
|
|
4
10
|
|
|
5
11
|
module Rails
|
|
6
12
|
# Implements the logic behind +Rails::Command::NotesCommand+. See <tt>rails notes --help</tt> for usage information.
|
|
@@ -16,24 +22,35 @@ module Rails
|
|
|
16
22
|
# Wraps a regular expression that will be tested against each of the source
|
|
17
23
|
# file's comments.
|
|
18
24
|
class ParserExtractor < Struct.new(:pattern)
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
if defined?(Prism)
|
|
26
|
+
def annotations(file)
|
|
27
|
+
result = Prism.parse_file(file)
|
|
28
|
+
return [] unless result.success?
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@comments = []
|
|
30
|
+
result.comments.filter_map do |comment|
|
|
31
|
+
Annotation.new(comment.location.start_line, $1, $2) if comment.location.slice =~ pattern
|
|
32
|
+
end
|
|
26
33
|
end
|
|
34
|
+
else
|
|
35
|
+
class Parser < Ripper
|
|
36
|
+
attr_reader :comments, :pattern
|
|
37
|
+
|
|
38
|
+
def initialize(source, pattern:)
|
|
39
|
+
super(source)
|
|
40
|
+
@pattern = pattern
|
|
41
|
+
@comments = []
|
|
42
|
+
end
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
def on_comment(value)
|
|
45
|
+
@comments << Annotation.new(lineno, $1, $2) if value =~ pattern
|
|
46
|
+
end
|
|
30
47
|
end
|
|
31
|
-
end
|
|
32
48
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
def annotations(file)
|
|
50
|
+
contents = File.read(file, encoding: Encoding::BINARY)
|
|
51
|
+
parser = Parser.new(contents, pattern: pattern).tap(&:parse)
|
|
52
|
+
parser.error? ? [] : parser.comments
|
|
53
|
+
end
|
|
37
54
|
end
|
|
38
55
|
end
|
|
39
56
|
|
|
@@ -1,32 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
STATS_DIRECTORIES
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
%w(Jobs app/jobs),
|
|
10
|
-
%w(Models app/models),
|
|
11
|
-
%w(Mailers app/mailers),
|
|
12
|
-
%w(Mailboxes app/mailboxes),
|
|
13
|
-
%w(Channels app/channels),
|
|
14
|
-
%w(Views app/views),
|
|
15
|
-
%w(JavaScripts app/assets/javascripts),
|
|
16
|
-
%w(Stylesheets app/assets/stylesheets),
|
|
17
|
-
%w(JavaScript app/javascript),
|
|
18
|
-
%w(Libraries lib/),
|
|
19
|
-
%w(APIs app/apis),
|
|
20
|
-
%w(Controller\ tests test/controllers),
|
|
21
|
-
%w(Helper\ tests test/helpers),
|
|
22
|
-
%w(Job\ tests test/jobs),
|
|
23
|
-
%w(Model\ tests test/models),
|
|
24
|
-
%w(Mailer\ tests test/mailers),
|
|
25
|
-
%w(Mailbox\ tests test/mailboxes),
|
|
26
|
-
%w(Channel\ tests test/channels),
|
|
27
|
-
%w(Integration\ tests test/integration),
|
|
28
|
-
%w(System\ tests test/system),
|
|
29
|
-
]
|
|
3
|
+
require "rails/code_statistics"
|
|
4
|
+
STATS_DIRECTORIES = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
|
|
5
|
+
Rails::CodeStatistics::DIRECTORIES,
|
|
6
|
+
"`STATS_DIRECTORIES` is deprecated and will be removed in Rails 8.1! Use `Rails::CodeStatistics.register_directory('My Directory', 'path/to/dir)` instead.",
|
|
7
|
+
Rails.deprecator
|
|
8
|
+
)
|
|
30
9
|
|
|
31
10
|
desc "Report code statistics (KLOCs, etc) from the application or engine"
|
|
32
11
|
task :stats do
|
|
@@ -34,5 +13,11 @@ task :stats do
|
|
|
34
13
|
stat_directories = STATS_DIRECTORIES.collect do |name, dir|
|
|
35
14
|
[ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ]
|
|
36
15
|
end.select { |name, dir| File.directory?(dir) }
|
|
37
|
-
|
|
16
|
+
|
|
17
|
+
$stderr.puts Rails.deprecator.warn(<<~MSG, caller_locations(0..1))
|
|
18
|
+
`bin/rake stats` has been deprecated and will be removed in Rails 8.1.
|
|
19
|
+
Please use `bin/rails stats` as Rails command instead.\n
|
|
20
|
+
MSG
|
|
21
|
+
|
|
22
|
+
Rails::CodeStatistics.new(*stat_directories).to_s
|
|
38
23
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
h2, p {
|
|
3
|
+
padding-left: 30px;
|
|
4
|
+
}
|
|
5
|
+
table {
|
|
6
|
+
margin: 0;
|
|
7
|
+
border-collapse: collapse;
|
|
8
|
+
word-wrap:break-word;
|
|
9
|
+
table-layout: fixed;
|
|
10
|
+
width:100%;
|
|
11
|
+
}
|
|
12
|
+
table thead tr {
|
|
13
|
+
border-bottom: 2px solid #ddd;
|
|
14
|
+
}
|
|
15
|
+
table th {
|
|
16
|
+
padding-left: 30px;
|
|
17
|
+
text-align: left;
|
|
18
|
+
}
|
|
19
|
+
table thead th.tag, table thead th.line-no {
|
|
20
|
+
width: 10%;
|
|
21
|
+
}
|
|
22
|
+
table tbody tr {
|
|
23
|
+
border-bottom: 1px solid #ddd;
|
|
24
|
+
}
|
|
25
|
+
table tbody tr:nth-child(odd) {
|
|
26
|
+
background: #f2f2f2;
|
|
27
|
+
}
|
|
28
|
+
table td {
|
|
29
|
+
padding: 4px 30px;
|
|
30
|
+
}
|
|
31
|
+
@media (prefers-color-scheme: dark) {
|
|
32
|
+
table tbody tr:nth-child(odd) {
|
|
33
|
+
background: #282828;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
37
|
+
|
|
38
|
+
<h2>
|
|
39
|
+
Notes
|
|
40
|
+
</h2>
|
|
41
|
+
|
|
42
|
+
<table id="route_table" class="table">
|
|
43
|
+
<thead>
|
|
44
|
+
<th>File Name</th>
|
|
45
|
+
<th class="line-no">Line No.</th>
|
|
46
|
+
<th class="tag">Tag</th>
|
|
47
|
+
<th>Description</th>
|
|
48
|
+
</thead>
|
|
49
|
+
<tbody>
|
|
50
|
+
<% @annotations.each do |file, annotations| %>
|
|
51
|
+
<% annotations.each.with_index do |annotation, index| %>
|
|
52
|
+
<tr>
|
|
53
|
+
<% if index == 0 %>
|
|
54
|
+
<th rowspan="<%= annotations.size %>">
|
|
55
|
+
<%= file %>
|
|
56
|
+
</th>
|
|
57
|
+
<% end %>
|
|
58
|
+
<td class="line-no"><%= annotation.line %></td>
|
|
59
|
+
<td class="tag"><%= annotation.tag %></td>
|
|
60
|
+
<td><%= annotation.text %></td>
|
|
61
|
+
</tr>
|
|
62
|
+
<% end %>
|
|
63
|
+
<% end %>
|
|
64
|
+
</tbody>
|
|
65
|
+
</table>
|
|
@@ -9,17 +9,13 @@ require "rails/test_unit/test_parser"
|
|
|
9
9
|
|
|
10
10
|
module Rails
|
|
11
11
|
module TestUnit
|
|
12
|
-
class InvalidTestError <
|
|
12
|
+
class InvalidTestError < StandardError
|
|
13
13
|
def initialize(path, suggestion)
|
|
14
|
-
super(<<~MESSAGE.
|
|
14
|
+
super(<<~MESSAGE.squish)
|
|
15
15
|
Could not load test file: #{path}.
|
|
16
16
|
#{suggestion}
|
|
17
17
|
MESSAGE
|
|
18
18
|
end
|
|
19
|
-
|
|
20
|
-
def backtrace(*args)
|
|
21
|
-
[]
|
|
22
|
-
end
|
|
23
19
|
end
|
|
24
20
|
|
|
25
21
|
class Runner
|
|
@@ -72,7 +68,7 @@ module Rails
|
|
|
72
68
|
if corrections.empty?
|
|
73
69
|
raise exception
|
|
74
70
|
end
|
|
75
|
-
raise
|
|
71
|
+
raise InvalidTestError.new(path, DidYouMean::Formatter.message_for(corrections))
|
|
76
72
|
else
|
|
77
73
|
raise
|
|
78
74
|
end
|
|
@@ -13,32 +13,29 @@ if defined?(Prism)
|
|
|
13
13
|
# Parse a test file to extract the line ranges of all tests in both
|
|
14
14
|
# method-style (def test_foo) and declarative-style (test "foo" do)
|
|
15
15
|
module TestParser
|
|
16
|
-
@begins_to_ends = {}
|
|
17
16
|
# Helper to translate a method object into the path and line range where
|
|
18
17
|
# the method was defined.
|
|
19
18
|
def self.definition_for(method)
|
|
20
19
|
filepath, start_line = method.source_location
|
|
21
|
-
|
|
22
|
-
return unless end_line = @begins_to_ends[filepath][start_line]
|
|
23
|
-
[filepath, start_line..end_line]
|
|
24
|
-
end
|
|
20
|
+
queue = [Prism.parse_file(filepath).value]
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
begins_to_ends[node.location.start_line] = node.location.end_line
|
|
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]
|
|
36
31
|
end
|
|
37
|
-
|
|
38
|
-
queue.concat(node.compact_child_nodes)
|
|
39
32
|
end
|
|
40
|
-
|
|
33
|
+
|
|
34
|
+
queue.concat(node.compact_child_nodes)
|
|
41
35
|
end
|
|
36
|
+
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
42
39
|
end
|
|
43
40
|
end
|
|
44
41
|
end
|