Class: StyleCapsule::ComponentBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/style_capsule/component_builder.rb

Overview

Builds CSS files from StyleCapsule components

This class extracts the logic from the rake task so it can be tested independently. The rake task delegates to this class.

Class Method Summary collapse

Class Method Details

.build_all(output_proc: nil) ⇒ Integer

Build CSS files for all components

Parameters:

  • output_proc (Proc, nil) (defaults to: nil)

    Optional proc to call with output messages

Returns:

  • (Integer)

    Number of files generated



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/style_capsule/component_builder.rb', line 127

def build_all(output_proc: nil)
  require "style_capsule/css_file_writer"

  # Ensure output directory exists
  CssFileWriter.ensure_output_directory

  # Collect all component classes that use StyleCapsule
  component_classes = collect_components

  # Generate CSS files for each component
  generated_count = 0
  component_classes.each do |component_class|
    file_path = build_component(component_class, output_proc: output_proc)
    generated_count += 1 if file_path
  end

  output_proc&.call("StyleCapsule CSS files built successfully")
  generated_count
end

.build_component(component_class, output_proc: nil) ⇒ String?

Build CSS file for a single component

rubocop:disable Metrics/AbcSize -- file build path with instrumentation and error handling

Parameters:

  • component_class (Class)

    Component class to build

  • output_proc (Proc, nil) (defaults to: nil)

    Optional proc to call with output messages

Returns:

  • (String, nil)

    Generated file path or nil if skipped



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/style_capsule/component_builder.rb', line 89

def build_component(component_class, output_proc: nil)
  return nil unless component_class.inline_cache_strategy == :file
  # Check for class method component_styles (required for file caching)
  return nil unless component_class.respond_to?(:component_styles, false)

  begin
    # Use class method component_styles for file caching
    css_content = component_class.component_styles
    return nil if css_content.nil? || css_content.to_s.strip.empty?

    # Create a temporary instance to get capsule
    # Some components might require arguments, so we catch errors
    instance = component_class.new
    capsule_id = instance.component_capsule
    scoped_css = instance.send(:scope_css, css_content)

    # Write CSS file
    file_path = CssFileWriter.write_css(
      css_content: scoped_css,
      component_class: component_class,
      capsule_id: capsule_id
    )

    output_proc&.call("Generated: #{file_path}") if file_path
    file_path
  rescue ArgumentError, NoMethodError => e
    # Component requires arguments or has dependencies - skip it (common for ViewComponent with required kwargs)
    warn "[style_capsule] Skipped #{component_class.name} in style_capsule:build — #{e.class}: #{e.message}"
    output_proc&.call("Skipped #{component_class.name}: #{e.message}")
    nil
  end
end

.collect_componentsArray<Class>

Collect all component classes that use StyleCapsule

Returns:

  • (Array<Class>)

    Array of component classes



79
80
81
# File 'lib/style_capsule/component_builder.rb', line 79

def collect_components
  find_phlex_components + find_view_components
end

.find_phlex_componentsArray<Class>

Find all Phlex components that use StyleCapsule

Uses ClassRegistry to find registered components (Rails-friendly, avoids expensive ObjectSpace scanning). Classes are automatically registered when they include StyleCapsule::Component.

Returns:

  • (Array<Class>)

    Array of component classes



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/style_capsule/component_builder.rb', line 28

def find_phlex_components
  return [] unless phlex_available?

  components = []

  # Use the registry (Rails-friendly, avoids expensive ObjectSpace scanning)
  ClassRegistry.each do |klass|
    if klass < Phlex::HTML && klass.included_modules.include?(StyleCapsule::Component)
      components << klass
    end
  rescue
    # Skip classes that cause errors (inheritance checks, etc.)
    next
  end

  components
end

.find_view_componentsArray<Class>

Find all ViewComponent components that use StyleCapsule

Uses ClassRegistry to find registered components (Rails-friendly, avoids expensive ObjectSpace scanning). Classes are automatically registered when they include StyleCapsule::ViewComponent.

Returns:

  • (Array<Class>)

    Array of component classes



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/style_capsule/component_builder.rb', line 52

def find_view_components
  return [] unless view_component_available?

  components = []

  begin
    # Use the registry (Rails-friendly, avoids expensive ObjectSpace scanning)
    ClassRegistry.each do |klass|
      if klass < ViewComponent::Base && klass.included_modules.include?(StyleCapsule::ViewComponent)
        components << klass
      end
    rescue
      # Skip classes that cause errors (inheritance checks, etc.)
      next
    end
  rescue
    # ViewComponent may have loading issues (e.g., version compatibility)
    # Silently skip ViewComponent components if there's an error
    # This allows the rake task to continue with Phlex components
  end

  components
end

.phlex_available?Boolean

Check if Phlex is available This method can be stubbed in tests to test fallback paths

Returns:

  • (Boolean)


12
13
14
# File 'lib/style_capsule/component_builder.rb', line 12

def phlex_available?
  !!defined?(Phlex::HTML)
end

.view_component_available?Boolean

Check if ViewComponent is available This method can be stubbed in tests to test fallback paths

Returns:

  • (Boolean)


18
19
20
# File 'lib/style_capsule/component_builder.rb', line 18

def view_component_available?
  !!defined?(ViewComponent::Base)
end