railties 7.2.3 → 8.0.5
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 +168 -256
- data/lib/minitest/rails_plugin.rb +8 -1
- data/lib/rails/application/bootstrap.rb +0 -1
- data/lib/rails/application/configuration.rb +17 -14
- data/lib/rails/application/default_middleware_stack.rb +4 -0
- data/lib/rails/application/finisher.rb +2 -3
- data/lib/rails/application/routes_reloader.rb +17 -3
- data/lib/rails/application.rb +10 -1
- data/lib/rails/application_controller.rb +2 -0
- data/lib/rails/backtrace_cleaner.rb +2 -2
- 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/command.rb +0 -6
- data/lib/rails/commands/app/update_command.rb +5 -9
- data/lib/rails/commands/console/irb_console.rb +3 -6
- 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 +2 -1
- data/lib/rails/commands/stats/stats_command.rb +19 -0
- data/lib/rails/console/methods.rb +5 -21
- data/lib/rails/dev_caching.rb +2 -2
- data/lib/rails/engine/configuration.rb +3 -1
- data/lib/rails/engine/lazy_route_set.rb +111 -0
- data/lib/rails/engine.rb +10 -6
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators/actions.rb +3 -3
- data/lib/rails/generators/app_base.rb +76 -56
- data/lib/rails/generators/base.rb +0 -4
- data/lib/rails/generators/bundle_helper.rb +34 -0
- 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/app/views/passwords/edit.html.erb +9 -0
- data/lib/rails/generators/erb/authentication/templates/app/views/passwords/new.html.erb +8 -0
- data/lib/rails/generators/erb/authentication/templates/app/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 +30 -30
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +23 -6
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +27 -12
- 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 -8
- data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +24 -1
- 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 +50 -0
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +30 -5
- data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +128 -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 +30 -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 +7 -2
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +12 -6
- 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/app/templates/ruby-version.tt +1 -1
- data/lib/rails/generators/rails/authentication/USAGE +6 -0
- data/lib/rails/generators/rails/authentication/authentication_generator.rb +60 -0
- data/lib/rails/generators/rails/authentication/templates/app/channels/application_cable/connection.rb.tt +16 -0
- data/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt +52 -0
- data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +33 -0
- data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +21 -0
- data/lib/rails/generators/rails/authentication/templates/app/mailers/passwords_mailer.rb.tt +6 -0
- data/lib/rails/generators/rails/authentication/templates/app/models/current.rb.tt +4 -0
- data/lib/rails/generators/rails/authentication/templates/app/models/session.rb.tt +3 -0
- data/lib/rails/generators/rails/authentication/templates/app/models/user.rb.tt +6 -0
- data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.html.erb.tt +4 -0
- data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.text.erb.tt +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 +12 -2
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +1 -1
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +5 -5
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -9
- data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +1 -1
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +3 -3
- data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
- 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/test_unit/authentication/authentication_generator.rb +18 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/fixtures/users.yml.tt +9 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +7 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +7 -0
- data/lib/rails/generators.rb +1 -0
- data/lib/rails/health_controller.rb +2 -0
- data/lib/rails/info.rb +2 -1
- 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 +37 -16
- data/lib/rails/tasks/statistics.rake +13 -28
- data/lib/rails/templates/rails/info/notes.html.erb +65 -0
- data/lib/rails/templates/rails/mailers/email.html.erb +1 -1
- data/lib/rails/test_unit/line_filtering.rb +24 -3
- data/lib/rails/test_unit/reporter.rb +8 -4
- data/lib/rails/test_unit/runner.rb +1 -0
- metadata +46 -37
- data/lib/rails/console/app.rb +0 -8
- data/lib/rails/console/helpers.rb +0 -8
- 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
|
@@ -15,7 +15,7 @@ module Rails
|
|
|
15
15
|
:cache_classes, :cache_store, :consider_all_requests_local, :console,
|
|
16
16
|
:eager_load, :exceptions_app, :file_watcher, :filter_parameters, :precompile_filter_parameters,
|
|
17
17
|
:force_ssl, :helpers_paths, :hosts, :host_authorization, :logger, :log_formatter,
|
|
18
|
-
:log_tags, :railties_order, :relative_url_root,
|
|
18
|
+
:log_tags, :silence_healthcheck_path, :railties_order, :relative_url_root,
|
|
19
19
|
:ssl_options, :public_file_server,
|
|
20
20
|
:session_options, :time_zone, :reload_classes_only_on_change,
|
|
21
21
|
:beginning_of_week, :filter_redirect, :x,
|
|
@@ -62,6 +62,7 @@ module Rails
|
|
|
62
62
|
@exceptions_app = nil
|
|
63
63
|
@autoflush_log = true
|
|
64
64
|
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
|
|
65
|
+
@silence_healthcheck_path = nil
|
|
65
66
|
@eager_load = nil
|
|
66
67
|
@secret_key_base = nil
|
|
67
68
|
@api_only = false
|
|
@@ -114,7 +115,9 @@ module Rails
|
|
|
114
115
|
action_controller.forgery_protection_origin_check = true
|
|
115
116
|
end
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
if respond_to?(:active_support)
|
|
119
|
+
active_support.to_time_preserves_timezone = :offset
|
|
120
|
+
end
|
|
118
121
|
|
|
119
122
|
if respond_to?(:active_record)
|
|
120
123
|
active_record.belongs_to_required_by_default = true
|
|
@@ -323,10 +326,6 @@ module Rails
|
|
|
323
326
|
|
|
324
327
|
self.yjit = true
|
|
325
328
|
|
|
326
|
-
if respond_to?(:active_job)
|
|
327
|
-
active_job.enqueue_after_transaction_commit = :default
|
|
328
|
-
end
|
|
329
|
-
|
|
330
329
|
if respond_to?(:active_storage)
|
|
331
330
|
active_storage.web_image_content_types = %w( image/png image/jpeg image/gif image/webp )
|
|
332
331
|
end
|
|
@@ -335,6 +334,18 @@ module Rails
|
|
|
335
334
|
active_record.postgresql_adapter_decode_dates = true
|
|
336
335
|
active_record.validate_migration_timestamps = true
|
|
337
336
|
end
|
|
337
|
+
when "8.0"
|
|
338
|
+
load_defaults "7.2"
|
|
339
|
+
|
|
340
|
+
if respond_to?(:active_support)
|
|
341
|
+
active_support.to_time_preserves_timezone = :zone
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
if respond_to?(:action_dispatch)
|
|
345
|
+
action_dispatch.strict_freshness = true
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
Regexp.timeout ||= 1 if Regexp.respond_to?(:timeout=)
|
|
338
349
|
else
|
|
339
350
|
raise "Unknown version #{target_version.to_s.inspect}"
|
|
340
351
|
end
|
|
@@ -354,14 +365,6 @@ module Rails
|
|
|
354
365
|
self.cache_classes = !value
|
|
355
366
|
end
|
|
356
367
|
|
|
357
|
-
def read_encrypted_secrets
|
|
358
|
-
Rails.deprecator.warn("'config.read_encrypted_secrets' is deprecated and will be removed in Rails 8.0.")
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
def read_encrypted_secrets=(value)
|
|
362
|
-
Rails.deprecator.warn("'config.read_encrypted_secrets=' is deprecated and will be removed in Rails 8.0.")
|
|
363
|
-
end
|
|
364
|
-
|
|
365
368
|
def encoding=(value)
|
|
366
369
|
@encoding = value
|
|
367
370
|
silence_warnings do
|
|
@@ -54,6 +54,10 @@ module Rails
|
|
|
54
54
|
middleware.use ::ActionDispatch::RequestId, header: config.action_dispatch.request_id_header
|
|
55
55
|
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
|
|
56
56
|
|
|
57
|
+
if path = config.silence_healthcheck_path
|
|
58
|
+
middleware.use ::Rails::Rack::SilenceRequest, path: path
|
|
59
|
+
end
|
|
60
|
+
|
|
57
61
|
middleware.use ::Rails::Rack::Logger, config.log_tags
|
|
58
62
|
middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app
|
|
59
63
|
middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
3
|
require "active_support/core_ext/string/inflections"
|
|
5
4
|
require "active_support/core_ext/array/conversions"
|
|
6
5
|
require "active_support/descendants_tracker"
|
|
@@ -143,6 +142,7 @@ module Rails
|
|
|
143
142
|
app.routes.prepend do
|
|
144
143
|
get "/rails/info/properties" => "rails/info#properties", internal: true
|
|
145
144
|
get "/rails/info/routes" => "rails/info#routes", internal: true
|
|
145
|
+
get "/rails/info/notes" => "rails/info#notes", internal: true
|
|
146
146
|
get "/rails/info" => "rails/info#index", internal: true
|
|
147
147
|
end
|
|
148
148
|
|
|
@@ -159,7 +159,6 @@ module Rails
|
|
|
159
159
|
initializer :set_routes_reloader_hook do |app|
|
|
160
160
|
reloader = routes_reloader
|
|
161
161
|
reloader.eager_load = app.config.eager_load
|
|
162
|
-
reloader.execute
|
|
163
162
|
reloaders << reloader
|
|
164
163
|
|
|
165
164
|
app.reloader.to_run do
|
|
@@ -177,7 +176,7 @@ module Rails
|
|
|
177
176
|
ActiveSupport.run_load_hooks(:after_routes_loaded, self)
|
|
178
177
|
end
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
reloader.execute_unless_loaded if !app.routes.is_a?(Engine::LazyRouteSet) || app.config.eager_load
|
|
181
180
|
end
|
|
182
181
|
|
|
183
182
|
# Set clearing dependencies after the finisher hook to ensure paths
|
|
@@ -7,16 +7,17 @@ module Rails
|
|
|
7
7
|
class RoutesReloader
|
|
8
8
|
include ActiveSupport::Callbacks
|
|
9
9
|
|
|
10
|
-
attr_reader :route_sets, :paths, :external_routes
|
|
10
|
+
attr_reader :route_sets, :paths, :external_routes, :loaded
|
|
11
11
|
attr_accessor :eager_load
|
|
12
|
-
attr_writer :run_after_load_paths # :nodoc:
|
|
13
|
-
delegate :execute_if_updated, :
|
|
12
|
+
attr_writer :run_after_load_paths, :loaded # :nodoc:
|
|
13
|
+
delegate :execute_if_updated, :updated?, to: :updater
|
|
14
14
|
|
|
15
15
|
def initialize
|
|
16
16
|
@paths = []
|
|
17
17
|
@route_sets = []
|
|
18
18
|
@external_routes = []
|
|
19
19
|
@eager_load = false
|
|
20
|
+
@loaded = false
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def reload!
|
|
@@ -28,6 +29,19 @@ module Rails
|
|
|
28
29
|
revert
|
|
29
30
|
end
|
|
30
31
|
|
|
32
|
+
def execute
|
|
33
|
+
@loaded = true
|
|
34
|
+
updater.execute
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def execute_unless_loaded
|
|
38
|
+
unless @loaded
|
|
39
|
+
execute
|
|
40
|
+
ActiveSupport.run_load_hooks(:after_routes_loaded, Rails.application)
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
31
45
|
private
|
|
32
46
|
def updater
|
|
33
47
|
@updater ||= begin
|
data/lib/rails/application.rb
CHANGED
|
@@ -9,6 +9,7 @@ require "active_support/deprecation"
|
|
|
9
9
|
require "active_support/encrypted_configuration"
|
|
10
10
|
require "active_support/hash_with_indifferent_access"
|
|
11
11
|
require "active_support/configuration_file"
|
|
12
|
+
require "active_support/parameter_filter"
|
|
12
13
|
require "rails/engine"
|
|
13
14
|
require "rails/autoloaders"
|
|
14
15
|
|
|
@@ -157,7 +158,15 @@ module Rails
|
|
|
157
158
|
|
|
158
159
|
# Reload application routes regardless if they changed or not.
|
|
159
160
|
def reload_routes!
|
|
160
|
-
routes_reloader.
|
|
161
|
+
if routes_reloader.execute_unless_loaded
|
|
162
|
+
routes_reloader.loaded = false
|
|
163
|
+
else
|
|
164
|
+
routes_reloader.reload!
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def reload_routes_unless_loaded # :nodoc:
|
|
169
|
+
initialized? && routes_reloader.execute_unless_loaded
|
|
161
170
|
end
|
|
162
171
|
|
|
163
172
|
# Returns a key generator (ActiveSupport::CachingKeyGenerator) for a
|
|
@@ -27,14 +27,14 @@ module Rails
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def clean(backtrace, kind = :silent)
|
|
30
|
-
|
|
30
|
+
return backtrace if ENV["BACKTRACE"]
|
|
31
31
|
|
|
32
32
|
super(backtrace, kind)
|
|
33
33
|
end
|
|
34
34
|
alias_method :filter, :clean
|
|
35
35
|
|
|
36
36
|
def clean_frame(frame, kind = :silent)
|
|
37
|
-
|
|
37
|
+
return frame if ENV["BACKTRACE"]
|
|
38
38
|
|
|
39
39
|
super(frame, kind)
|
|
40
40
|
end
|
|
@@ -3,115 +3,157 @@
|
|
|
3
3
|
require "rails/code_statistics_calculator"
|
|
4
4
|
require "active_support/core_ext/enumerable"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
module Rails
|
|
7
|
+
class CodeStatistics
|
|
8
|
+
DIRECTORIES = [
|
|
9
|
+
%w(Controllers app/controllers),
|
|
10
|
+
%w(Helpers app/helpers),
|
|
11
|
+
%w(Jobs app/jobs),
|
|
12
|
+
%w(Models app/models),
|
|
13
|
+
%w(Mailers app/mailers),
|
|
14
|
+
%w(Mailboxes app/mailboxes),
|
|
15
|
+
%w(Channels app/channels),
|
|
16
|
+
%w(Views app/views),
|
|
17
|
+
%w(JavaScripts app/assets/javascripts),
|
|
18
|
+
%w(Stylesheets app/assets/stylesheets),
|
|
19
|
+
%w(JavaScript app/javascript),
|
|
20
|
+
%w(Libraries lib/),
|
|
21
|
+
%w(APIs app/apis),
|
|
22
|
+
%w(Controller\ tests test/controllers),
|
|
23
|
+
%w(Helper\ tests test/helpers),
|
|
24
|
+
%w(Job\ tests test/jobs),
|
|
25
|
+
%w(Model\ tests test/models),
|
|
26
|
+
%w(Mailer\ tests test/mailers),
|
|
27
|
+
%w(Mailbox\ tests test/mailboxes),
|
|
28
|
+
%w(Channel\ tests test/channels),
|
|
29
|
+
%w(Integration\ tests test/integration),
|
|
30
|
+
%w(System\ tests test/system),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
TEST_TYPES = ["Controller tests",
|
|
34
|
+
"Helper tests",
|
|
35
|
+
"Model tests",
|
|
36
|
+
"Mailer tests",
|
|
37
|
+
"Mailbox tests",
|
|
38
|
+
"Channel tests",
|
|
39
|
+
"Job tests",
|
|
40
|
+
"Integration tests",
|
|
41
|
+
"System tests"]
|
|
42
|
+
|
|
43
|
+
HEADERS = { lines: " Lines", code_lines: " LOC", classes: "Classes", methods: "Methods" }
|
|
44
|
+
|
|
45
|
+
class_attribute :directories, default: DIRECTORIES
|
|
46
|
+
class_attribute :test_types, default: TEST_TYPES
|
|
47
|
+
|
|
48
|
+
# Add directories to the output of the <tt>bin/rails stats</tt> command.
|
|
49
|
+
#
|
|
50
|
+
# Rails::CodeStatistics.register_directory("My Directory", "path/to/dir")
|
|
51
|
+
#
|
|
52
|
+
# For directories that contain test code, set the <tt>test_directory</tt> argument to true.
|
|
53
|
+
#
|
|
54
|
+
# Rails::CodeStatistics.register_directory("Model specs", "spec/models", test_directory: true)
|
|
55
|
+
def self.register_directory(label, path, test_directory: false)
|
|
56
|
+
self.directories << [label, path]
|
|
57
|
+
self.test_types << label if test_directory
|
|
58
|
+
end
|
|
24
59
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
60
|
+
def initialize(*pairs)
|
|
61
|
+
@pairs = pairs
|
|
62
|
+
@statistics = calculate_statistics
|
|
63
|
+
@total = calculate_total if pairs.length > 1
|
|
64
|
+
end
|
|
29
65
|
|
|
30
|
-
|
|
31
|
-
|
|
66
|
+
def to_s
|
|
67
|
+
print_header
|
|
68
|
+
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
|
|
32
69
|
print_splitter
|
|
33
|
-
end
|
|
34
70
|
|
|
35
|
-
|
|
36
|
-
|
|
71
|
+
if @total
|
|
72
|
+
print_line("Total", @total)
|
|
73
|
+
print_splitter
|
|
74
|
+
end
|
|
37
75
|
|
|
38
|
-
|
|
39
|
-
def calculate_statistics
|
|
40
|
-
Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }]
|
|
76
|
+
print_code_test_stats
|
|
41
77
|
end
|
|
42
78
|
|
|
43
|
-
|
|
44
|
-
|
|
79
|
+
private
|
|
80
|
+
def calculate_statistics
|
|
81
|
+
Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|ts|css|scss|coffee|rake|erb)$/)
|
|
85
|
+
stats = Rails::CodeStatisticsCalculator.new
|
|
45
86
|
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
Dir.foreach(directory) do |file_name|
|
|
88
|
+
path = "#{directory}/#{file_name}"
|
|
48
89
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
if File.directory?(path) && !file_name.start_with?(".")
|
|
91
|
+
stats.add(calculate_directory_statistics(path, pattern))
|
|
92
|
+
elsif file_name&.match?(pattern)
|
|
93
|
+
stats.add_by_file_path(path)
|
|
94
|
+
end
|
|
53
95
|
end
|
|
54
|
-
end
|
|
55
96
|
|
|
56
|
-
|
|
57
|
-
|
|
97
|
+
stats
|
|
98
|
+
end
|
|
58
99
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
100
|
+
def calculate_total
|
|
101
|
+
@statistics.each_with_object(Rails::CodeStatisticsCalculator.new) do |pair, total|
|
|
102
|
+
total.add(pair.last)
|
|
103
|
+
end
|
|
62
104
|
end
|
|
63
|
-
end
|
|
64
105
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
106
|
+
def calculate_code
|
|
107
|
+
code_loc = 0
|
|
108
|
+
@statistics.each { |k, v| code_loc += v.code_lines unless test_types.include? k }
|
|
109
|
+
code_loc
|
|
110
|
+
end
|
|
70
111
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
112
|
+
def calculate_tests
|
|
113
|
+
test_loc = 0
|
|
114
|
+
@statistics.each { |k, v| test_loc += v.code_lines if test_types.include? k }
|
|
115
|
+
test_loc
|
|
116
|
+
end
|
|
76
117
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
118
|
+
def width_for(label)
|
|
119
|
+
[@statistics.values.sum { |s| s.public_send(label) }.to_s.size, HEADERS[label].length].max
|
|
120
|
+
end
|
|
80
121
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
122
|
+
def print_header
|
|
123
|
+
print_splitter
|
|
124
|
+
print "| Name "
|
|
125
|
+
HEADERS.each do |k, v|
|
|
126
|
+
print " | #{v.rjust(width_for(k))}"
|
|
127
|
+
end
|
|
128
|
+
puts " | M/C | LOC/M |"
|
|
129
|
+
print_splitter
|
|
86
130
|
end
|
|
87
|
-
puts " | M/C | LOC/M |"
|
|
88
|
-
print_splitter
|
|
89
|
-
end
|
|
90
131
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
132
|
+
def print_splitter
|
|
133
|
+
print "+----------------------"
|
|
134
|
+
HEADERS.each_key do |k|
|
|
135
|
+
print "+#{'-' * (width_for(k) + 2)}"
|
|
136
|
+
end
|
|
137
|
+
puts "+-----+-------+"
|
|
95
138
|
end
|
|
96
|
-
puts "+-----+-------+"
|
|
97
|
-
end
|
|
98
139
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
140
|
+
def print_line(name, statistics)
|
|
141
|
+
m_over_c = (statistics.methods / statistics.classes) rescue 0
|
|
142
|
+
loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue 0
|
|
102
143
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
144
|
+
print "| #{name.ljust(20)} "
|
|
145
|
+
HEADERS.each_key do |k|
|
|
146
|
+
print "| #{statistics.send(k).to_s.rjust(width_for(k))} "
|
|
147
|
+
end
|
|
148
|
+
puts "| #{m_over_c.to_s.rjust(3)} | #{loc_over_m.to_s.rjust(5)} |"
|
|
106
149
|
end
|
|
107
|
-
puts "| #{m_over_c.to_s.rjust(3)} | #{loc_over_m.to_s.rjust(5)} |"
|
|
108
|
-
end
|
|
109
150
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
151
|
+
def print_code_test_stats
|
|
152
|
+
code = calculate_code
|
|
153
|
+
tests = calculate_tests
|
|
113
154
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
155
|
+
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f / code)}"
|
|
156
|
+
puts ""
|
|
157
|
+
end
|
|
158
|
+
end
|
|
117
159
|
end
|
|
@@ -1,97 +1,99 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
module Rails
|
|
4
|
+
class CodeStatisticsCalculator # :nodoc:
|
|
5
|
+
attr_reader :lines, :code_lines, :classes, :methods
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
7
|
+
PATTERNS = {
|
|
8
|
+
rb: {
|
|
9
|
+
line_comment: /^\s*#/,
|
|
10
|
+
begin_block_comment: /^=begin/,
|
|
11
|
+
end_block_comment: /^=end/,
|
|
12
|
+
class: /^\s*class\s+[_A-Z]/,
|
|
13
|
+
method: /^\s*def\s+[_a-z]/,
|
|
14
|
+
},
|
|
15
|
+
erb: {
|
|
16
|
+
line_comment: %r{((^\s*<%#.*%>)|(<!--.*-->))},
|
|
17
|
+
},
|
|
18
|
+
css: {
|
|
19
|
+
line_comment: %r{^\s*/\*.*\*/},
|
|
20
|
+
},
|
|
21
|
+
scss: {
|
|
22
|
+
line_comment: %r{((^\s*/\*.*\*/)|(^\s*//))},
|
|
23
|
+
},
|
|
24
|
+
js: {
|
|
25
|
+
line_comment: %r{^\s*//},
|
|
26
|
+
begin_block_comment: %r{^\s*/\*},
|
|
27
|
+
end_block_comment: %r{\*/},
|
|
28
|
+
method: /function(\s+[_a-zA-Z][\da-zA-Z]*)?\s*\(/,
|
|
29
|
+
},
|
|
30
|
+
coffee: {
|
|
31
|
+
line_comment: /^\s*#/,
|
|
32
|
+
begin_block_comment: /^\s*###/,
|
|
33
|
+
end_block_comment: /^\s*###/,
|
|
34
|
+
class: /^\s*class\s+[_A-Z]/,
|
|
35
|
+
method: /[-=]>/,
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
|
-
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
PATTERNS[:minitest] = PATTERNS[:rb].merge method: /^\s*(def|test)\s+['"_a-z]/
|
|
40
|
+
PATTERNS[:rake] = PATTERNS[:rb]
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
def initialize(lines = 0, code_lines = 0, classes = 0, methods = 0)
|
|
43
|
+
@lines = lines
|
|
44
|
+
@code_lines = code_lines
|
|
45
|
+
@classes = classes
|
|
46
|
+
@methods = methods
|
|
47
|
+
end
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
def add(code_statistics_calculator)
|
|
50
|
+
@lines += code_statistics_calculator.lines
|
|
51
|
+
@code_lines += code_statistics_calculator.code_lines
|
|
52
|
+
@classes += code_statistics_calculator.classes
|
|
53
|
+
@methods += code_statistics_calculator.methods
|
|
54
|
+
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
def add_by_file_path(file_path)
|
|
57
|
+
File.open(file_path) do |f|
|
|
58
|
+
add_by_io(f, file_type(file_path))
|
|
59
|
+
end
|
|
58
60
|
end
|
|
59
|
-
end
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
def add_by_io(io, file_type)
|
|
63
|
+
patterns = PATTERNS[file_type] || {}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
comment_started = false
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
while line = io.gets
|
|
68
|
+
@lines += 1
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
next
|
|
74
|
-
else
|
|
75
|
-
if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line)
|
|
76
|
-
comment_started = true
|
|
70
|
+
if comment_started
|
|
71
|
+
if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line)
|
|
72
|
+
comment_started = false
|
|
73
|
+
end
|
|
77
74
|
next
|
|
75
|
+
else
|
|
76
|
+
if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line)
|
|
77
|
+
comment_started = true
|
|
78
|
+
next
|
|
79
|
+
end
|
|
78
80
|
end
|
|
79
|
-
end
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
@classes += 1 if patterns[:class] && patterns[:class].match?(line)
|
|
83
|
+
@methods += 1 if patterns[:method] && patterns[:method].match?(line)
|
|
84
|
+
if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment]))
|
|
85
|
+
@code_lines += 1
|
|
86
|
+
end
|
|
85
87
|
end
|
|
86
88
|
end
|
|
87
|
-
end
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
private
|
|
91
|
+
def file_type(file_path)
|
|
92
|
+
if file_path.end_with? "_test.rb"
|
|
93
|
+
:minitest
|
|
94
|
+
else
|
|
95
|
+
File.extname(file_path).delete_prefix(".").downcase.to_sym
|
|
96
|
+
end
|
|
95
97
|
end
|
|
96
|
-
|
|
98
|
+
end
|
|
97
99
|
end
|
|
@@ -16,7 +16,7 @@ module Rails
|
|
|
16
16
|
if editor.to_s.empty?
|
|
17
17
|
say "No $VISUAL or $EDITOR to open file in. Assign one like this:"
|
|
18
18
|
say ""
|
|
19
|
-
say %(VISUAL="
|
|
19
|
+
say %(VISUAL="code --wait" #{executable(current_subcommand)})
|
|
20
20
|
say ""
|
|
21
21
|
say "For editors that fork and exit immediately, it's important to pass a wait flag;"
|
|
22
22
|
say "otherwise, the file will be saved immediately with no chance to edit."
|
data/lib/rails/command.rb
CHANGED
|
@@ -23,12 +23,6 @@ module Rails
|
|
|
23
23
|
super(message)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
if !Exception.method_defined?(:detailed_message) # Ruby 3.2+
|
|
27
|
-
def detailed_message(...)
|
|
28
|
-
message
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
26
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
|
33
27
|
include DidYouMean::Correctable
|
|
34
28
|
|