Skip to content

Commit d5b153b

Browse files
justin808claude
andcommitted
Improve shakapacker detection with robust multi-strategy approach
Enhanced shakapacker_in_gemfile? method to use layered detection: 1. Check Gem.loaded_specs (fastest) 2. Parse Gemfile.lock (most accurate, handles git/path gems) 3. Query Bundler.load.specs (reliable when available) 4. Fallback to Gemfile parsing This approach is more efficient, avoids side effects from require(), and handles edge cases better than the previous implementation. Co-authored-by: User <[email protected]> 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent d6ca545 commit d5b153b

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

lib/generators/react_on_rails/install_generator.rb

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,20 +182,37 @@ def ensure_shakapacker_installed
182182
File.write(".shakapacker_just_installed", "")
183183
end
184184

185+
# Checks whether "shakapacker" is present in the *current bundle*,
186+
# without loading it. Prioritizes Gemfile.lock (cheap + accurate),
187+
# then Bundler's resolved specs, and finally a light Gemfile scan.
185188
def shakapacker_in_gemfile?
186-
return false unless File.exist?("Gemfile")
189+
gem_name = "shakapacker"
190+
gemfile = ENV["BUNDLE_GEMFILE"] || "Gemfile"
191+
lockfile = File.join(File.dirname(gemfile), "Gemfile.lock")
187192

188-
gemfile_content = File.read("Gemfile")
189-
return true if gemfile_content.match?(/gem\s+['"]shakapacker['"]/)
193+
# 1) Already loaded in this process?
194+
return true if Gem.loaded_specs.key?(gem_name)
190195

191-
# Also check if shakapacker is already available in the current bundle
192-
# This handles cases where it might be loaded from parent environments
196+
# 2) Present in the lockfile? (handles git/path gems too)
197+
if File.file?(lockfile)
198+
# Lines look like: " shakapacker (x.y.z)"
199+
return true if File.foreach(lockfile).any? { |l| l.match?(/^\s{4}#{Regexp.escape(gem_name)}\s\(/) }
200+
end
201+
202+
# 3) Ask Bundler for resolved specs (doesn't require the gem code)
193203
begin
194-
require "shakapacker"
195-
true
196-
rescue LoadError
197-
false
204+
require "bundler"
205+
return true if Bundler.load.specs.any? { |s| s.name == gem_name }
206+
rescue StandardError
207+
# Fall through if Bundler isn't available or load fails
208+
end
209+
210+
# 4) Fallback: direct Gemfile mention (not perfect, but cheap)
211+
if File.file?(gemfile)
212+
return true if File.foreach(gemfile).any? { |l| l.match?(/^\s*gem\s+['"]#{Regexp.escape(gem_name)}['"]/) }
198213
end
214+
215+
false
199216
end
200217

201218
def add_bin_scripts

0 commit comments

Comments
 (0)