a-nti_manner_kick_course 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4dc6a3d6c4947ef0ed61f061101a08fbce40cb114e6a8e27f10445d3c3d77ba9
4
+ data.tar.gz: ad23ea7057ba5e40f4a4830c363aab4b73c18678292e83dd06894c049c803da1
5
+ SHA512:
6
+ metadata.gz: 5e43b59506830ae8320db2ea37c5a87d28967f43399982492196b14bc4fc10b51aa23058875c04b269769a9d96048071ef2d6d79d86c43904234256d12e8662b
7
+ data.tar.gz: aa4d12b64c793bf21480abd45364f54ad2d2c881846cd4493ca23d2617f35f84844a8109b8d78d95980c3d5746025bedeba7493dc0c2e0df0b47134e098dc02d
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright Shinichi Maeshima
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # A::NtiMannerKickCourse
2
+
3
+ Rails speeds up the startup process by lazily loading classes for components like ActiveRecord::Base and ActionController::Base. Additionally, the behavior of lazy loading is essential for applying configuration settings to these components. Without lazy loading, some configurations might not be applied as expected.
4
+
5
+ For example, consider the following scenario:
6
+
7
+ When upgrading from Rails 7.0 to Rails 7.1, running rails app:upgrade generates a file named `config/initializers/new_framework_defaults_7_1.rb`. This file helps incrementally enable new default settings for Rails 7.1. Initially, all settings in this file are commented out. Uncommenting the following setting will enable it:
8
+
9
+ ```ruby
10
+ ###
11
+ # Do not treat an `ActionController::Parameters` instance
12
+ # as equal to an equivalent `Hash` by default.
13
+ #++
14
+ Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
15
+ ````
16
+
17
+ As the comment suggests, this setting ensures that ActionController::Parameters instances are no longer treated as equivalent to Hash. However, if ActionController::Base is eager-loaded, this configuration will not behave as expected. Why does this happen?
18
+
19
+ Configuration settings like `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality` are not automatically effective. These settings are applied to components like ActionController only during the Rails initialization process.
20
+
21
+ In this case, the value of `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality` is assigned to `ActionController::Parameters.allow_deprecated_parameters_hash_equality` during initialization, as seen in the following code:
22
+
23
+ ```ruby
24
+ ActionController::Parameters.allow_deprecated_parameters_hash_equality = Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality
25
+ ```
26
+
27
+ Source: https://github.com/rails/rails/blob/36c1591bcb5e0ee3084759c7f42a706fe5bb7ca7/actionpack/lib/action_controller/railtie.rb#L51-L52
28
+
29
+ This assignment is wrapped in an `ActiveSupport.on_load(:action_controller, run_once: true) do ... end` block, ensuring that it runs only when ActionController::Base is loaded:
30
+
31
+ ```ruby
32
+ ActiveSupport.on_load(:action_controller, run_once: true) do
33
+ # Configuration assignment logic
34
+ end
35
+ ````
36
+
37
+ Now, consider a gem "add_some_function_to_controller" with the following code:
38
+
39
+ ```ruby
40
+ module AddSomeFunctionToController
41
+ # snip
42
+ end
43
+
44
+ ActionController::Base.include(AddSomeFunctionToController)
45
+ ```
46
+
47
+ Since all gems listed in the Gemfile are required in config/application.rb, the above code causes ActionController::Base to be loaded during Rails initialization. The order of initialization typically looks like this:
48
+
49
+ 1. config/application.rb
50
+ 2. Component configuration logic (e.g., applying settings)
51
+ 3. Initializer files in config/initializers/*.rb
52
+
53
+ As a result, the configuration logic for ActionController is executed before the initializer file `config/initializers/new_framework_defaults_7_1.rb`. This means that the setting `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false` is not applied in time.
54
+
55
+ Fixing the Issue
56
+
57
+ To solve this, modify the gem code as follows:
58
+
59
+ ```ruby
60
+ module AddSomeFunctionToController
61
+ # snip
62
+ end
63
+
64
+ ActiveSupport.on_load(:action_controller) do
65
+ ActionController::Base.include(AddSomeFunctionToController)
66
+ end
67
+ ```
68
+
69
+ This ensures that ActionController::Base is loaded lazily, delaying the execution of the configuration logic to the correct timing. The updated order of initialization becomes:
70
+
71
+ 1. config/application.rb
72
+ 2. Initializer files in config/initializers/*.rb
73
+ 3. Component configuration logic
74
+
75
+ This resolves the issue, as the setting in config/initializers/new_framework_defaults_7_1.rb is now applied correctly.
76
+
77
+ While this specific case is likely a common issue, other problems may also arise from changes to the initialization order. To ensure reliable behavior, it is critical to keep all component loading deferred during Rails initialization. However, manually checking for potential issues with lazy loading is impractical.
78
+
79
+ Using a-nti_manner_kick_course can help detect libraries or application code (like add_some_function_to_controller) that interfere with lazy loading, allowing you to maintain proper initialization behavior.
80
+
81
+ ## Installation
82
+
83
+ Add this line **at the top of your Gemfile**.
84
+
85
+ ```ruby
86
+ gem "a-nti_manner_kick_course"
87
+ ```
88
+
89
+ > [!IMPORTANT]
90
+ > To detect gems that fail to defer execution, you need to add this gem at the top of your Gemfile.
91
+
92
+ And then execute:
93
+ ```bash
94
+ $ bundle
95
+ ```
96
+
97
+ ## Usage
98
+
99
+ Start your Rails application with the ANTI_MANNER environment variable as follows.
100
+
101
+ ```bash
102
+ $ ANTI_MANNER=1 rails boot
103
+ ```
104
+
105
+ If you are using Rails 7.1 or below, start the application as follows.
106
+
107
+ ```bash
108
+ $ ANTI_MANNER=1 rails runner 1
109
+ ```
110
+
111
+ If any code fails to lazy loading, the process will exit with status code 1. This command suggests which lines are eager loading Rails code. It is a good idea to regularly check in CI if lazy loading is working correctly.
112
+
113
+ You can fix the issue by wrapping the relevant code in an `ActiveSupport.on_load` block.
114
+
115
+ For more details about ActiveSupport.on_load, check [the official Rails documentation]((https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html).
116
+
117
+ If the ANTI_MANNER environment variable is not set, this gem does nothing.
118
+
119
+
120
+ ## License
121
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,16 @@
1
+ require "rails"
2
+
3
+ module A
4
+ module NtiMannerKickCourse
5
+ class Railtie < ::Rails::Railtie
6
+ initializer "anti_manner", before: :eager_load! do
7
+ if A::NtiMannerKickCourse.enabled?
8
+ A::NtiMannerKickCourse.finish_monitoring
9
+
10
+ puts "Congratulations! No code was found that fails to defer execution!"
11
+ exit
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module A
2
+ module NtiMannerKickCourse
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,92 @@
1
+ require "a/nti_manner_kick_course/version"
2
+ require "a/nti_manner_kick_course/railtie"
3
+
4
+ module A
5
+ module NtiMannerKickCourse
6
+ MONITORED_HOOKS = %i[
7
+ action_controller action_controller_base action_controller_api action_controller_test_case action_dispatch_response action_dispatch_integration_test
8
+ message_pack active_model active_model_translation active_job active_job_test_case active_record_fixtures
9
+ action_cable_connection action_cable_connection_test_case action_cable action_cable_channel action_cable_channel_test_case
10
+ action_text_encrypted_rich_text action_text_record action_text_rich_text action_text_content active_record active_record_fixture_set
11
+ active_record_sqlite3adapter active_record_mysql2adapter active_record_trilogyadapter active_record_postgresqladapter active_record_encryption
12
+ action_view action_view_test_case action_mailer action_mailer_test_case active_storage_blog active_storage_record active_storage_variant_record
13
+ active_storage_attachment action_mailbox_inbound_email action_mailbox_record action_mailbox action_mailbox_test_case
14
+ ].freeze
15
+
16
+ class << self
17
+ def enabled?
18
+ ENV["ANTI_MANNER"]
19
+ end
20
+
21
+ def debug?
22
+ ENV["ANTI_MANNER_DEBUG"]
23
+ end
24
+
25
+ def monitor
26
+ require "active_support/lazy_load_hooks"
27
+
28
+ start_monitoring
29
+
30
+ MONITORED_HOOKS.each do |framework|
31
+ ActiveSupport.on_load(framework) do
32
+ if A::NtiMannerKickCourse.monitoring? && !A::NtiMannerKickCourse.already_checked?
33
+ A::NtiMannerKickCourse.already_checked
34
+ message = if A::NtiMannerKickCourse.debug?
35
+ <<~"MESSAGE"
36
+ During Rails startup, the block inside ActiveSupport.on_load(#{framework}) was executed.
37
+ There is code that is not being deferred as expected.
38
+
39
+ Currently, debug mode is enabled, so the full stack trace is being displayed.
40
+ To show only the suspicious code line, remove the ANTI_MANNER_DEBUG environment variable and rerun.
41
+
42
+ #{caller}
43
+ MESSAGE
44
+ else
45
+ suspect = caller.find { |c| !A::NtiMannerKickCourse.filtering.match?(c) }
46
+ <<~"MESSAGE"
47
+ During Rails startup, the block inside ActiveSupport.on_load(#{framework}) was executed.
48
+ There is code that is not being deferred as expected. The suspicious part is here.
49
+
50
+ #{suspect}
51
+
52
+ If you want to check the entire stack trace, set the ANTI_MANNER_DEBUG environment variable.
53
+ MESSAGE
54
+ end
55
+
56
+ abort(message)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def monitoring?
63
+ @monitoring
64
+ end
65
+
66
+ def finish_monitoring
67
+ @monitoring = false
68
+ end
69
+
70
+ # TODO: We need to make this list more comprehensive.
71
+ def filtering
72
+ %r{<internal:|/bundled_gems.rb|/(activesupport|actionpack|activerecord|bootsnap|bundler|zeitwerk)-[0-9a-z\.]+/}
73
+ end
74
+
75
+ def already_checked?
76
+ @already_checked
77
+ end
78
+
79
+ def already_checked
80
+ @already_checked = true
81
+ end
82
+
83
+ private
84
+
85
+ def start_monitoring
86
+ @monitoring = true
87
+ end
88
+ end
89
+
90
+ monitor if enabled?
91
+ end
92
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :a_nti_manner_kick_course do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: a-nti_manner_kick_course
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shinichi Maeshima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.0
27
+ description: This library detects code or gems that violate lazy loading conventions
28
+ during Rails initialization.
29
+ email:
30
+ - netwillnet@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - lib/a/nti_manner_kick_course.rb
39
+ - lib/a/nti_manner_kick_course/railtie.rb
40
+ - lib/a/nti_manner_kick_course/version.rb
41
+ - lib/tasks/a/nti_manner_kick_course_tasks.rake
42
+ homepage: https://github.com/willnet/a-nti_manner_kick_course
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ homepage_uri: https://github.com/willnet/a-nti_manner_kick_course
47
+ source_code_uri: https://github.com/willnet/a-nti_manner_kick_course
48
+ changelog_uri: https://github.com/willnet/a-nti_manner_kick_course/releases
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.5.22
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: This library detects code or gems that violate lazy loading conventions during
68
+ Rails initialization.
69
+ test_files: []