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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +168 -256
  3. data/lib/minitest/rails_plugin.rb +8 -1
  4. data/lib/rails/application/bootstrap.rb +0 -1
  5. data/lib/rails/application/configuration.rb +17 -14
  6. data/lib/rails/application/default_middleware_stack.rb +4 -0
  7. data/lib/rails/application/finisher.rb +2 -3
  8. data/lib/rails/application/routes_reloader.rb +17 -3
  9. data/lib/rails/application.rb +10 -1
  10. data/lib/rails/application_controller.rb +2 -0
  11. data/lib/rails/backtrace_cleaner.rb +2 -2
  12. data/lib/rails/code_statistics.rb +128 -86
  13. data/lib/rails/code_statistics_calculator.rb +78 -76
  14. data/lib/rails/command/helpers/editor.rb +1 -1
  15. data/lib/rails/command.rb +0 -6
  16. data/lib/rails/commands/app/update_command.rb +5 -9
  17. data/lib/rails/commands/console/irb_console.rb +3 -6
  18. data/lib/rails/commands/credentials/USAGE +4 -4
  19. data/lib/rails/commands/credentials/credentials_command.rb +5 -1
  20. data/lib/rails/commands/dev/dev_command.rb +1 -1
  21. data/lib/rails/commands/devcontainer/devcontainer_command.rb +2 -1
  22. data/lib/rails/commands/stats/stats_command.rb +19 -0
  23. data/lib/rails/console/methods.rb +5 -21
  24. data/lib/rails/dev_caching.rb +2 -2
  25. data/lib/rails/engine/configuration.rb +3 -1
  26. data/lib/rails/engine/lazy_route_set.rb +111 -0
  27. data/lib/rails/engine.rb +10 -6
  28. data/lib/rails/gem_version.rb +3 -3
  29. data/lib/rails/generators/actions.rb +3 -3
  30. data/lib/rails/generators/app_base.rb +76 -56
  31. data/lib/rails/generators/base.rb +0 -4
  32. data/lib/rails/generators/bundle_helper.rb +34 -0
  33. data/lib/rails/generators/database.rb +101 -67
  34. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  35. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/edit.html.erb +9 -0
  36. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/new.html.erb +8 -0
  37. data/lib/rails/generators/erb/authentication/templates/app/views/sessions/new.html.erb +11 -0
  38. data/lib/rails/generators/generated_attribute.rb +16 -11
  39. data/lib/rails/generators/rails/app/app_generator.rb +30 -30
  40. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +23 -6
  41. data/lib/rails/generators/rails/app/templates/Gemfile.tt +27 -12
  42. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
  43. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +10 -3
  44. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  45. data/lib/rails/generators/rails/app/templates/bin/setup.tt +5 -8
  46. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  47. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +24 -1
  48. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +23 -0
  49. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +50 -0
  50. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +30 -5
  51. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +128 -0
  52. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -23
  53. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +31 -51
  54. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -19
  55. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
  56. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  57. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +30 -0
  58. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -2
  59. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -3
  60. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +4 -3
  61. data/lib/rails/generators/rails/app/templates/dockerignore.tt +7 -2
  62. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +12 -6
  63. data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -2
  64. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
  65. data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
  66. data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
  67. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +113 -65
  68. data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
  69. data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
  70. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  71. data/lib/rails/generators/rails/app/templates/public/icon.svg +2 -2
  72. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  73. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  74. data/lib/rails/generators/rails/authentication/authentication_generator.rb +60 -0
  75. data/lib/rails/generators/rails/authentication/templates/app/channels/application_cable/connection.rb.tt +16 -0
  76. data/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt +52 -0
  77. data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +33 -0
  78. data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +21 -0
  79. data/lib/rails/generators/rails/authentication/templates/app/mailers/passwords_mailer.rb.tt +6 -0
  80. data/lib/rails/generators/rails/authentication/templates/app/models/current.rb.tt +4 -0
  81. data/lib/rails/generators/rails/authentication/templates/app/models/session.rb.tt +3 -0
  82. data/lib/rails/generators/rails/authentication/templates/app/models/user.rb.tt +6 -0
  83. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.html.erb.tt +4 -0
  84. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.text.erb.tt +2 -0
  85. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
  86. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  87. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +12 -2
  88. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +1 -1
  89. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +5 -5
  90. data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -9
  91. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +1 -1
  92. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +3 -3
  93. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  94. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
  95. data/lib/rails/generators/rails/script/USAGE +18 -0
  96. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  97. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  98. data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +18 -0
  99. data/lib/rails/generators/test_unit/authentication/templates/test/fixtures/users.yml.tt +9 -0
  100. data/lib/rails/generators/test_unit/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +7 -0
  101. data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +7 -0
  102. data/lib/rails/generators.rb +1 -0
  103. data/lib/rails/health_controller.rb +2 -0
  104. data/lib/rails/info.rb +2 -1
  105. data/lib/rails/info_controller.rb +10 -4
  106. data/lib/rails/rack/silence_request.rb +33 -0
  107. data/lib/rails/rack.rb +1 -0
  108. data/lib/rails/source_annotation_extractor.rb +37 -16
  109. data/lib/rails/tasks/statistics.rake +13 -28
  110. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  111. data/lib/rails/templates/rails/mailers/email.html.erb +1 -1
  112. data/lib/rails/test_unit/line_filtering.rb +24 -3
  113. data/lib/rails/test_unit/reporter.rb +8 -4
  114. data/lib/rails/test_unit/runner.rb +1 -0
  115. metadata +46 -37
  116. data/lib/rails/console/app.rb +0 -8
  117. data/lib/rails/console/helpers.rb +0 -8
  118. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
  119. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
  120. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
  121. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +0 -70
  122. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
  123. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
  124. data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
  125. data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
  126. 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
- ActiveSupport.to_time_preserves_timezone = true
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
- ActiveSupport.run_load_hooks(:after_routes_loaded, self)
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, :execute, :updated?, to: :updater
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
@@ -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.reload!
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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "action_controller"
4
+
3
5
  class Rails::ApplicationController < ActionController::Base # :nodoc:
4
6
  prepend_view_path File.expand_path("templates", __dir__)
5
7
  layout "application"
@@ -27,14 +27,14 @@ module Rails
27
27
  end
28
28
 
29
29
  def clean(backtrace, kind = :silent)
30
- kind = nil if ENV["BACKTRACE"]
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
- kind = nil if ENV["BACKTRACE"]
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
- class CodeStatistics # :nodoc:
7
- TEST_TYPES = ["Controller tests",
8
- "Helper tests",
9
- "Model tests",
10
- "Mailer tests",
11
- "Mailbox tests",
12
- "Channel tests",
13
- "Job tests",
14
- "Integration tests",
15
- "System tests"]
16
-
17
- HEADERS = { lines: " Lines", code_lines: " LOC", classes: "Classes", methods: "Methods" }
18
-
19
- def initialize(*pairs)
20
- @pairs = pairs
21
- @statistics = calculate_statistics
22
- @total = calculate_total if pairs.length > 1
23
- end
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
- def to_s
26
- print_header
27
- @pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
28
- print_splitter
60
+ def initialize(*pairs)
61
+ @pairs = pairs
62
+ @statistics = calculate_statistics
63
+ @total = calculate_total if pairs.length > 1
64
+ end
29
65
 
30
- if @total
31
- print_line("Total", @total)
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
- print_code_test_stats
36
- end
71
+ if @total
72
+ print_line("Total", @total)
73
+ print_splitter
74
+ end
37
75
 
38
- private
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
- def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|ts|css|scss|coffee|rake|erb)$/)
44
- stats = CodeStatisticsCalculator.new
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
- Dir.foreach(directory) do |file_name|
47
- path = "#{directory}/#{file_name}"
87
+ Dir.foreach(directory) do |file_name|
88
+ path = "#{directory}/#{file_name}"
48
89
 
49
- if File.directory?(path) && !file_name.start_with?(".")
50
- stats.add(calculate_directory_statistics(path, pattern))
51
- elsif file_name&.match?(pattern)
52
- stats.add_by_file_path(path)
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
- stats
57
- end
97
+ stats
98
+ end
58
99
 
59
- def calculate_total
60
- @statistics.each_with_object(CodeStatisticsCalculator.new) do |pair, total|
61
- total.add(pair.last)
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
- def calculate_code
66
- code_loc = 0
67
- @statistics.each { |k, v| code_loc += v.code_lines unless TEST_TYPES.include? k }
68
- code_loc
69
- end
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
- def calculate_tests
72
- test_loc = 0
73
- @statistics.each { |k, v| test_loc += v.code_lines if TEST_TYPES.include? k }
74
- test_loc
75
- end
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
- def width_for(label)
78
- [@statistics.values.sum { |s| s.public_send(label) }.to_s.size, HEADERS[label].length].max
79
- end
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
- def print_header
82
- print_splitter
83
- print "| Name "
84
- HEADERS.each do |k, v|
85
- print " | #{v.rjust(width_for(k))}"
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
- def print_splitter
92
- print "+----------------------"
93
- HEADERS.each_key do |k|
94
- print "+#{'-' * (width_for(k) + 2)}"
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
- def print_line(name, statistics)
100
- m_over_c = (statistics.methods / statistics.classes) rescue 0
101
- loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue 0
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
- print "| #{name.ljust(20)} "
104
- HEADERS.each_key do |k|
105
- print "| #{statistics.send(k).to_s.rjust(width_for(k))} "
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
- def print_code_test_stats
111
- code = calculate_code
112
- tests = calculate_tests
151
+ def print_code_test_stats
152
+ code = calculate_code
153
+ tests = calculate_tests
113
154
 
114
- puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f / code)}"
115
- puts ""
116
- end
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
- class CodeStatisticsCalculator # :nodoc:
4
- attr_reader :lines, :code_lines, :classes, :methods
3
+ module Rails
4
+ class CodeStatisticsCalculator # :nodoc:
5
+ attr_reader :lines, :code_lines, :classes, :methods
5
6
 
6
- PATTERNS = {
7
- rb: {
8
- line_comment: /^\s*#/,
9
- begin_block_comment: /^=begin/,
10
- end_block_comment: /^=end/,
11
- class: /^\s*class\s+[_A-Z]/,
12
- method: /^\s*def\s+[_a-z]/,
13
- },
14
- erb: {
15
- line_comment: %r{((^\s*<%#.*%>)|(<!--.*-->))},
16
- },
17
- css: {
18
- line_comment: %r{^\s*/\*.*\*/},
19
- },
20
- scss: {
21
- line_comment: %r{((^\s*/\*.*\*/)|(^\s*//))},
22
- },
23
- js: {
24
- line_comment: %r{^\s*//},
25
- begin_block_comment: %r{^\s*/\*},
26
- end_block_comment: %r{\*/},
27
- method: /function(\s+[_a-zA-Z][\da-zA-Z]*)?\s*\(/,
28
- },
29
- coffee: {
30
- line_comment: /^\s*#/,
31
- begin_block_comment: /^\s*###/,
32
- end_block_comment: /^\s*###/,
33
- class: /^\s*class\s+[_A-Z]/,
34
- method: /[-=]>/,
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
- PATTERNS[:minitest] = PATTERNS[:rb].merge method: /^\s*(def|test)\s+['"_a-z]/
39
- PATTERNS[:rake] = PATTERNS[:rb]
39
+ PATTERNS[:minitest] = PATTERNS[:rb].merge method: /^\s*(def|test)\s+['"_a-z]/
40
+ PATTERNS[:rake] = PATTERNS[:rb]
40
41
 
41
- def initialize(lines = 0, code_lines = 0, classes = 0, methods = 0)
42
- @lines = lines
43
- @code_lines = code_lines
44
- @classes = classes
45
- @methods = methods
46
- end
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
- def add(code_statistics_calculator)
49
- @lines += code_statistics_calculator.lines
50
- @code_lines += code_statistics_calculator.code_lines
51
- @classes += code_statistics_calculator.classes
52
- @methods += code_statistics_calculator.methods
53
- end
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
- def add_by_file_path(file_path)
56
- File.open(file_path) do |f|
57
- add_by_io(f, file_type(file_path))
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
- def add_by_io(io, file_type)
62
- patterns = PATTERNS[file_type] || {}
62
+ def add_by_io(io, file_type)
63
+ patterns = PATTERNS[file_type] || {}
63
64
 
64
- comment_started = false
65
+ comment_started = false
65
66
 
66
- while line = io.gets
67
- @lines += 1
67
+ while line = io.gets
68
+ @lines += 1
68
69
 
69
- if comment_started
70
- if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line)
71
- comment_started = false
72
- end
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
- @classes += 1 if patterns[:class] && patterns[:class].match?(line)
82
- @methods += 1 if patterns[:method] && patterns[:method].match?(line)
83
- if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment]))
84
- @code_lines += 1
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
- private
90
- def file_type(file_path)
91
- if file_path.end_with? "_test.rb"
92
- :minitest
93
- else
94
- File.extname(file_path).delete_prefix(".").downcase.to_sym
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
- end
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="mate --wait" #{executable(current_subcommand)})
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