Skip to content

Commit eabd2ff

Browse files
justin808claude
andcommitted
Address code review feedback
Changes based on PR review comments: 1. Add logging when skipping generate_packs due to shakapacker hook - Now prints message during assets:precompile to inform users 2. Document PackGenerator design decisions - Explain why it delegates to Rake task (stable interface) - Clarify two execution strategies (direct vs bundle exec) - Justify class naming as semantic wrapper 3. Improve error handling documentation - Explain why errors are swallowed (fail-safe approach) - List possible error types (NoMethodError, TypeError, etc.) - Add debug warning when detection fails 4. Add comprehensive test documentation - Overview of PackGenerator responsibilities - Explanation of what tests cover and why - Clear structure for future contributors 5. Reduce cyclomatic complexity - Extract helper methods for hook detection - Separate concerns (extraction vs validation) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 2ecec4a commit eabd2ff

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

lib/react_on_rails/configuration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ def adjust_precompile_task
239239

240240
precompile_tasks = lambda {
241241
# Skip generate_packs if shakapacker has a precompile hook configured
242-
unless ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
242+
if ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
243+
puts "Skipping react_on_rails:generate_packs (configured in shakapacker precompile hook)"
244+
else
243245
Rake::Task["react_on_rails:generate_packs"].invoke
244246
end
245247

lib/react_on_rails/dev/pack_generator.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@
55

66
module ReactOnRails
77
module Dev
8+
# PackGenerator triggers the generation of React on Rails packs
9+
#
10+
# Design decisions:
11+
# 1. Why trigger via Rake task instead of direct Ruby code?
12+
# - The actual pack generation logic lives in lib/react_on_rails/packs_generator.rb
13+
# - The rake task (lib/tasks/generate_packs.rake) provides a stable, documented interface
14+
# - This allows the implementation to evolve without breaking bin/dev
15+
# - Users can also run the task directly: `rake react_on_rails:generate_packs`
16+
#
17+
# 2. Why two execution strategies (direct vs bundle exec)?
18+
# - Direct Rake execution: Faster when already in Bundler/Rails context (bin/dev)
19+
# - Bundle exec fallback: Required when called outside Rails context
20+
# - This optimization avoids subprocess overhead in the common case
21+
#
22+
# 3. Why is the class named "PackGenerator" when it delegates?
23+
# - It's a semantic wrapper around pack generation for the dev workflow
24+
# - Provides a clean API for bin/dev without exposing Rake internals
25+
# - Handles hook detection, error handling, and output formatting
826
class PackGenerator
927
class << self
1028
def generate(verbose: false)

lib/react_on_rails/packer_utils.rb

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,23 +169,38 @@ def self.raise_shakapacker_version_incompatible_for_basic_pack_generation
169169

170170
# Check if shakapacker.yml has a precompile hook configured
171171
# This prevents react_on_rails from running generate_packs twice
172+
#
173+
# Returns false if detection fails for any reason (missing shakapacker, malformed config, etc.)
174+
# to ensure generate_packs runs rather than being incorrectly skipped
172175
def self.shakapacker_precompile_hook_configured?
173176
return false unless defined?(::Shakapacker)
174177

178+
hooks = extract_precompile_hooks
179+
return false if hooks.nil?
180+
181+
hook_contains_generate_packs?(hooks)
182+
rescue StandardError => e
183+
# Swallow errors during hook detection to fail safe - if we can't detect the hook,
184+
# we should run generate_packs rather than skip it incorrectly.
185+
# Possible errors: NoMethodError (config method missing), TypeError (unexpected data structure),
186+
# or errors from shakapacker's internal implementation changes
187+
warn "Warning: Unable to detect shakapacker precompile hook: #{e.message}" if ENV["DEBUG"]
188+
false
189+
end
190+
191+
def self.extract_precompile_hooks
175192
# Access config data using private :data method since there's no public API
176193
# to access the raw configuration hash needed for hook detection
177194
config_data = ::Shakapacker.config.send(:data)
178195

179196
# Try symbol keys first (Shakapacker's internal format), then fall back to string keys
180-
hooks = config_data&.dig(:hooks, :precompile) || config_data&.dig("hooks", "precompile")
181-
182-
return false if hooks.nil?
197+
config_data&.dig(:hooks, :precompile) || config_data&.dig("hooks", "precompile")
198+
end
183199

200+
def self.hook_contains_generate_packs?(hooks)
184201
# Check if any hook contains the generate_packs rake task using word boundary
185202
# to avoid false positives from comments or similar strings
186203
Array(hooks).any? { |hook| hook.to_s.match?(/\breact_on_rails:generate_packs\b/) }
187-
rescue StandardError
188-
false
189204
end
190205
end
191206
end

spec/react_on_rails/dev/pack_generator_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
require_relative "../spec_helper"
44
require "react_on_rails/dev/pack_generator"
55

6+
# Tests for PackGenerator.generate which triggers pack generation for react_on_rails
7+
#
8+
# This class is responsible for:
9+
# 1. Detecting if shakapacker has a precompile hook configured and skipping if so
10+
# 2. Choosing the optimal execution strategy (direct Rake task vs bundle exec)
11+
# 3. Handling errors appropriately and providing user-friendly output
12+
#
13+
# Test coverage includes:
14+
# - Shakapacker hook detection (skip generation when hook is configured)
15+
# - Direct Rake execution in Bundler context (faster, no subprocess overhead)
16+
# - Fallback to bundle exec when Rails/Bundler not available
17+
# - Error handling with proper stderr output
18+
# - Silent mode output suppression
619
RSpec.describe ReactOnRails::Dev::PackGenerator do
720
describe ".generate" do
821
before do

0 commit comments

Comments
 (0)