Skip to content

Commit

Permalink
Isolate and namespace StimulusReflex::Installer (#699)
Browse files Browse the repository at this point in the history
This pull request isolates the methods defined
`lib/stimulus_reflex/installer.rb` into a `StimulusReflex::Installer`
constant so they don't pollute the global namespace if the file is
required.

CableReady got a similar PR:
stimulusreflex/cable_ready#295

## Why should this be added

Exposing all the methods from the installer in the global namespace
could lead to issues down the road. Methods like `options` are likely to
be overridden.
  • Loading branch information
marcoroth authored May 6, 2024
1 parent 004355b commit e2451ee
Show file tree
Hide file tree
Showing 28 changed files with 612 additions and 586 deletions.
4 changes: 2 additions & 2 deletions lib/generators/stimulus_reflex/stimulus_reflex_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ def execute

template(reflex_src, reflex_path) unless options[:skip_reflex]

if !options[:skip_stimulus] && entrypoint.blank?
if !options[:skip_stimulus] && StimulusReflex::Installer.entrypoint.blank?
puts "❌ You must specify a valid JavaScript entrypoint."
exit
end

stimulus_controller_src = "app/javascript/controllers/%file_name%_controller.js.tt"
stimulus_controller_path = Rails.root.join(entrypoint, "controllers/#{file_name}_controller.js")
stimulus_controller_path = Rails.root.join(StimulusReflex::Installer.entrypoint, "controllers/#{file_name}_controller.js")

template(stimulus_controller_src, stimulus_controller_path) unless options[:skip_stimulus]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%- if bundler.importmap? -%>
<%- if StimulusReflex::Installer.bundler.importmap? -%>
import consumer from "channels/consumer"
<%- else -%>
import consumer from "../channels/consumer"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%- if bundler.importmap? -%>
<%- if StimulusReflex::Installer.bundler.importmap? -%>
import "config/cable_ready"
import "config/stimulus_reflex"
<%- else -%>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%- if bundler.importmap? -%>
<%- if StimulusReflex::Installer.bundler.importmap? -%>
import { application } from "controllers/application"
import controller from "controllers/application_controller"
<%- else -%>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%- if bundler.importmap? -%>
<%- if StimulusReflex::Installer.bundler.importmap? -%>
import ApplicationController from "controllers/application_controller"
<%- else -%>
import ApplicationController from "./application_controller"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Application } from "@hotwired/stimulus"
<%- if bundler.importmap? %>
<%- if StimulusReflex::Installer.bundler.importmap? %>
import consumer from "channels/consumer"
<%- else %>
import consumer from "../channels/consumer"
Expand Down
60 changes: 30 additions & 30 deletions lib/install/action_cable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
if defined?(ActionCable::Engine)
say "⏩ ActionCable::Engine is already loaded and in scope. Skipping"
else
halt "ActionCable::Engine is not loaded, please add or uncomment `require \"action_cable/engine\"` to your `config/application.rb`"
StimulusReflex::Installer.halt "ActionCable::Engine is not loaded, please add or uncomment `require \"action_cable/engine\"` to your `config/application.rb`"
return
end

return if pack_path_missing?
return if StimulusReflex::Installer.pack_path_missing?

# verify that the Action Cable pubsub config is created
cable_config = Rails.root.join("config/cable.yml")
Expand All @@ -37,37 +37,37 @@
"url" => "<%= ENV.fetch(\"REDIS_URL\") { \"redis://localhost:6379/1\" } %>",
"channel_prefix" => "#{app_name}_development"
}
backup(cable_config) do
StimulusReflex::Installer.backup(cable_config) do
cable_config.write(yaml.to_yaml)
end
say "✅ config/cable.yml was updated to use the redis adapter in development"
else
say "🤷 config/cable.yml should use the redis adapter - or something like it - in development. You have something else specified, and we trust that you know what you're doing."
end

if gemfile.match?(/gem ['"]redis['"]/)
if StimulusReflex::Installer.gemfile.match?(/gem ['"]redis['"]/)
say "⏩ redis gem is already present in Gemfile. Skipping."
elsif Rails::VERSION::MAJOR >= 7
add_gem "redis@~> 5"
StimulusReflex::Installer.add_gem "redis@~> 5"
else
add_gem "redis@~> 4"
StimulusReflex::Installer.add_gem "redis@~> 4"
end

# install action-cable-redis-backport gem if using Action Cable < 7.1
unless ActionCable::VERSION::MAJOR >= 7 && ActionCable::VERSION::MINOR >= 1
if gemfile.match?(/gem ['"]action-cable-redis-backport['"]/)
if StimulusReflex::Installer.gemfile.match?(/gem ['"]action-cable-redis-backport['"]/)
say "⏩ action-cable-redis-backport gem is already present in Gemfile. Skipping."
else
add_gem "action-cable-redis-backport@~> 1"
StimulusReflex::Installer.add_gem "action-cable-redis-backport@~> 1"
end
end

# verify that the Action Cable channels folder and consumer class is available
step_path = "/app/javascript/channels/"
channels_path = Rails.root.join(entrypoint, "channels")
consumer_src = fetch(step_path, "consumer.js.tt")
channels_path = Rails.root.join(StimulusReflex::Installer.entrypoint, "channels")
consumer_src = StimulusReflex::Installer.fetch(step_path, "consumer.js.tt")
consumer_path = channels_path / "consumer.js"
index_src = fetch(step_path, "index.js.#{bundler}.tt")
index_src = StimulusReflex::Installer.fetch(step_path, "index.js.#{StimulusReflex::Installer.bundler}.tt")
index_path = channels_path / "index.js"
friendly_index_path = index_path.relative_path_from(Rails.root).to_s

Expand All @@ -79,7 +79,7 @@
if index_path.read == index_src.read
say "⏩ #{friendly_index_path} is already present. Skipping."
else
backup(index_path) do
StimulusReflex::Installer.backup(index_path) do
copy_file(index_src, index_path, verbose: false)
end
say "✅ #{friendly_index_path} has been updated"
Expand All @@ -92,45 +92,45 @@
# import Action Cable channels into application pack
channels_pattern = /import ['"](\.\.\/|\.\/)?channels['"]/
channels_commented_pattern = /\s*\/\/\s*#{channels_pattern}/
channel_import = "import \"#{prefix}channels\"\n"
channel_import = "import \"#{StimulusReflex::Installer.prefix}channels\"\n"

if pack.match?(channels_pattern)
if pack.match?(channels_commented_pattern)
proceed = if options.key? "uncomment"
options["uncomment"]
if StimulusReflex::Installer.pack.match?(channels_pattern)
if StimulusReflex::Installer.pack.match?(channels_commented_pattern)
proceed = if StimulusReflex::Installer.options.key? "uncomment"
StimulusReflex::Installer.options["uncomment"]
else
!no?("✨ Action Cable seems to be commented out in your application.js. Do you want to uncomment it? (Y/n)")
end

if proceed
# uncomment_lines only works with Ruby comments 🙄
lines = pack_path.readlines
lines = StimulusReflex::Installer.pack_path.readlines
matches = lines.select { |line| line =~ channels_commented_pattern }
lines[lines.index(matches.last).to_i] = channel_import
pack_path.write lines.join
say "✅ Uncommented channels import in #{friendly_pack_path}"
StimulusReflex::Installer.pack_path.write lines.join
say "✅ Uncommented channels import in #{StimulusReflex::Installer.friendly_pack_path}"
else
say "🤷 your Action Cable channels are not being imported in your application.js. We trust that you have a reason for this."
end
else
say "⏩ channels are already being imported in #{friendly_pack_path}. Skipping."
say "⏩ channels are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping."
end
else
lines = pack_path.readlines
lines = StimulusReflex::Installer.pack_path.readlines
matches = lines.select { |line| line =~ /^import / }
lines.insert lines.index(matches.last).to_i + 1, channel_import
pack_path.write lines.join
say "✅ channels imported in #{friendly_pack_path}"
StimulusReflex::Installer.pack_path.write lines.join
say "✅ channels imported in #{StimulusReflex::Installer.friendly_pack_path}"
end

# create working copy of Action Cable initializer in tmp
if action_cable_initializer_path.exist?
FileUtils.cp(action_cable_initializer_path, action_cable_initializer_working_path)
if StimulusReflex::Installer.action_cable_initializer_path.exist?
FileUtils.cp(StimulusReflex::Installer.action_cable_initializer_path, StimulusReflex::Installer.action_cable_initializer_working_path)

say "⏩ Action Cable initializer already exists. Skipping"
else
# create Action Cable initializer if it doesn't already exist
create_file(action_cable_initializer_working_path, verbose: false) do
create_file(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do
<<~RUBY
# frozen_string_literal: true
Expand All @@ -140,10 +140,10 @@
end

# silence notoriously chatty Action Cable logs
if action_cable_initializer_working_path.read.match?(/^[^#]*ActionCable.server.config.logger/)
if StimulusReflex::Installer.action_cable_initializer_working_path.read.match?(/^[^#]*ActionCable.server.config.logger/)
say "⏩ Action Cable logger is already being silenced. Skipping"
else
append_file(action_cable_initializer_working_path, verbose: false) do
append_file(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do
<<~RUBY
ActionCable.server.config.logger = Logger.new(nil)
Expand All @@ -152,4 +152,4 @@
say "✅ Action Cable logger silenced for performance and legibility"
end

complete_step :action_cable
StimulusReflex::Installer.complete_step :action_cable
22 changes: 11 additions & 11 deletions lib/install/broadcaster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def needs_broadcaster?(path)
channel_path = Rails.root.join("app/channels/application_cable/channel.rb")
controller_path = Rails.root.join("app/controllers/application_controller.rb")
job_path = Rails.root.join("app/jobs/application_job.rb")
model_path = Rails.root.join(application_record_path)
model_path = Rails.root.join(StimulusReflex::Installer.application_record_path)

include_in_channel = needs_broadcaster?(channel_path)
include_in_controller = needs_broadcaster?(controller_path)
Expand All @@ -21,20 +21,20 @@ def needs_broadcaster?(path)
proceed = [include_in_channel, include_in_controller, include_in_job, include_in_model].reduce(:|)

unless proceed
complete_step :broadcaster
StimulusReflex::Installer.complete_step :broadcaster

puts "⏩ CableReady::Broadcaster already included in all files. Skipping."
return
end

proceed = if options.key? "broadcaster"
options["broadcaster"]
proceed = if StimulusReflex::Installer.options.key? "broadcaster"
StimulusReflex::Installer.options["broadcaster"]
else
!no?("✨ Make CableReady::Broadcaster available to channels, controllers, jobs and models? (Y/n)")
end

unless proceed
complete_step :broadcaster
StimulusReflex::Installer.complete_step :broadcaster

puts "⏩ Skipping."
return
Expand All @@ -44,7 +44,7 @@ def needs_broadcaster?(path)

# include CableReady::Broadcaster in Action Cable Channel classes
if include_in_channel
backup(channel_path) do
StimulusReflex::Installer.backup(channel_path) do
inject_into_file channel_path, broadcaster_include, after: /class (ApplicationCable::)?Channel < ActionCable::Channel::Base/, verbose: false
end

Expand All @@ -55,7 +55,7 @@ def needs_broadcaster?(path)

# include CableReady::Broadcaster in Action Controller classes
if include_in_controller
backup(controller_path) do
StimulusReflex::Installer.backup(controller_path) do
inject_into_class controller_path, "ApplicationController", broadcaster_include, verbose: false
end

Expand All @@ -67,7 +67,7 @@ def needs_broadcaster?(path)
# include CableReady::Broadcaster in Active Job classes, if present

if include_in_job
backup(job_path) do
StimulusReflex::Installer.backup(job_path) do
inject_into_class job_path, "ApplicationJob", broadcaster_include, verbose: false
end

Expand All @@ -78,13 +78,13 @@ def needs_broadcaster?(path)

# include CableReady::Broadcaster in Active Record model classes
if include_in_model
backup(application_record_path) do
inject_into_class application_record_path, "ApplicationRecord", broadcaster_include, verbose: false
StimulusReflex::Installer.backup(StimulusReflex::Installer.application_record_path) do
inject_into_class StimulusReflex::Installer.application_record_path, "ApplicationRecord", broadcaster_include, verbose: false
end

puts "✅ include CableReady::Broadcaster in ApplicationRecord"
else
puts "⏩ Not including CableReady::Broadcaster in ApplicationRecord. Skipping"
end

complete_step :broadcaster
StimulusReflex::Installer.complete_step :broadcaster
18 changes: 9 additions & 9 deletions lib/install/bundle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

require "stimulus_reflex/installer"

hash = gemfile_hash
hash = StimulusReflex::Installer.gemfile_hash

# run bundle only when gems are waiting to be added or removed
add = add_gem_list.exist? ? add_gem_list.readlines.map(&:chomp) : []
remove = remove_gem_list.exist? ? remove_gem_list.readlines.map(&:chomp) : []
add = StimulusReflex::Installer.add_gem_list.exist? ? StimulusReflex::Installer.add_gem_list.readlines.map(&:chomp) : []
remove = StimulusReflex::Installer.remove_gem_list.exist? ? StimulusReflex::Installer.remove_gem_list.readlines.map(&:chomp) : []

if add.present? || remove.present?
lines = gemfile_path.readlines
lines = StimulusReflex::Installer.gemfile_path.readlines

remove.each do |name|
index = lines.index { |line| line =~ /gem ['"]#{name}['"]/ }
Expand Down Expand Up @@ -40,17 +40,17 @@
end
end

gemfile_path.write lines.join
StimulusReflex::Installer.gemfile_path.write lines.join

bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1") if hash != gemfile_hash
bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1") if hash != StimulusReflex::Installer.gemfile_hash
else
say "⏩ No rubygems depedencies to install. Skipping."
end

FileUtils.cp(development_working_path, development_path)
FileUtils.cp(StimulusReflex::Installer.development_working_path, StimulusReflex::Installer.development_path)
say "✅ development environment configuration installed"

FileUtils.cp(action_cable_initializer_working_path, action_cable_initializer_path)
FileUtils.cp(StimulusReflex::Installer.action_cable_initializer_working_path, StimulusReflex::Installer.action_cable_initializer_path)
say "✅ Action Cable initializer installed"

complete_step :bundle
StimulusReflex::Installer.complete_step :bundle
10 changes: 5 additions & 5 deletions lib/install/compression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

require "stimulus_reflex/installer"

initializer = action_cable_initializer_working_path.read
initializer = StimulusReflex::Installer.action_cable_initializer_working_path.read

if gemfile.match?(/gem ['"]permessage_deflate['"]/)
if StimulusReflex::Installer.gemfile.match?(/gem ['"]permessage_deflate['"]/)
say "⏩ permessage_deflate already present in Gemfile. Skipping."
else
add_gem "permessage_deflate@>= 0.1"
StimulusReflex::Installer.add_gem "permessage_deflate@>= 0.1"
end

# add permessage_deflate config to Action Cable initializer
if initializer.exclude? "PermessageDeflate.configure"
create_or_append(action_cable_initializer_working_path, verbose: false) do
StimulusReflex::Installer.create_or_append(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do
<<~RUBY
module ActionCable
module Connection
Expand All @@ -38,4 +38,4 @@ def initialize(env, event_target, event_loop, protocols)
say "⏩ Action Cable initializer is already patched to deflate websocket traffic. Skipping."
end

complete_step :compression
StimulusReflex::Installer.complete_step :compression
Loading

0 comments on commit e2451ee

Please sign in to comment.