style_capsule 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ca5bf9bf535558147384d22380ad4b54c6b21f85054e578a84f74d35f1d6296
4
- data.tar.gz: 93c5a155435df7d39f6a2a739d0e6c0be1b99274bf8ebf658e2aab76f065bda1
3
+ metadata.gz: d1fcbe6c03f9675593d6dca7b3d7d70de2b7d471d2d938993b59877614332ff4
4
+ data.tar.gz: 6aa5feb7ff25ef755084e7754f328e4340a0d4dc620e1ea8298badbb0387f254
5
5
  SHA512:
6
- metadata.gz: 34c0a4456e242d881d0c74ca58a726ad66f953ef2fddb41ba5d38fd98219588b6ed85cd07afa2fe352b34d3c75666496af28b6c2e94bbc8b24edcc65823738b3
7
- data.tar.gz: 8cac6b0eb300d2030883313d70d69fc16063630bc9dd4efac6ed4396049814187aa83abe56b14d753baabb9afdc3eb3a0c7ce14aba8c49543aa9b7e4ce7ca381
6
+ metadata.gz: f06af1e47282aa0220b5ff28e5e0a197a8d76eaa9f3c00639958ca1f9d672c7ad1dd4f672b9de83cc7c521af6a49b9c9f9c9bd0ce476575211b1fc7a7aeb1da2
7
+ data.tar.gz: 3844dd9da6608b1eff6e495e19b92e3f90d4b41df323118f5fa7c6216603d3b33620c80df8aeb13c2e2506e133e3ab6e424c3dfd76feb16dbbc68b37fac72636
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.2.0 (2025-11-24)
4
+
5
+ - Added `StyleCapsule::ClassRegistry` for Rails-friendly class tracking without ObjectSpace iteration
6
+ - Fixed development environment bug where `ObjectSpace.each_object(Class)` could trigger errors with gems that override `Class#name` (e.g., Faker)
7
+ - Improved `ComponentBuilder` to use ClassRegistry first, with ObjectSpace fallback for compatibility
8
+ - Classes are now automatically registered when including `StyleCapsule::Component` or `StyleCapsule::ViewComponent`
9
+ - Better performance in development mode by tracking only relevant classes instead of iterating all classes
10
+ - Enhanced error handling for classes that cause issues during iteration
11
+
3
12
  ## 1.1.0 (2025-11-21)
4
13
 
5
14
  - Made Rails dependencies optional: `railties` and `activesupport` moved to development dependencies
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # style_capsule
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/style_capsule.svg?v=1.1.0)](https://badge.fury.io/rb/style_capsule) [![Test Status](https://github.com/amkisko/style_capsule.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/style_capsule.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/style_capsule.rb/graph/badge.svg?token=2U6NXJOVVM)](https://codecov.io/gh/amkisko/style_capsule.rb)
3
+ [![Gem Version](https://badge.fury.io/rb/style_capsule.svg?v=1.2.0)](https://badge.fury.io/rb/style_capsule) [![Test Status](https://github.com/amkisko/style_capsule.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/style_capsule.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/style_capsule.rb/graph/badge.svg?token=2U6NXJOVVM)](https://codecov.io/gh/amkisko/style_capsule.rb)
4
4
 
5
5
  CSS scoping extension for Ruby components. Provides attribute-based style encapsulation for Phlex, ViewComponent, and ERB templates to prevent style leakage between components. Works with Rails and can be used standalone in other Ruby frameworks (Sinatra, Hanami, etc.) or plain Ruby scripts. Includes configurable caching strategies for optimal performance.
6
6
 
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StyleCapsule
4
+ # Registry for tracking classes that include StyleCapsule modules
5
+ #
6
+ # This provides a Rails-friendly way to track classes without using ObjectSpace,
7
+ # which can be problematic with certain gems (e.g., Faker) that override Class#name.
8
+ #
9
+ # Classes are automatically registered when they include StyleCapsule::Component
10
+ # or StyleCapsule::ViewComponent.
11
+ #
12
+ # @example
13
+ # # Classes are automatically registered when they include modules
14
+ # class MyComponent < ApplicationComponent
15
+ # include StyleCapsule::Component # Automatically registered
16
+ # end
17
+ #
18
+ # # Iterate over registered classes
19
+ # StyleCapsule::ClassRegistry.each do |klass|
20
+ # klass.clear_css_cache if klass.respond_to?(:clear_css_cache)
21
+ # end
22
+ #
23
+ # # Clear registry (useful in development when classes are reloaded)
24
+ # StyleCapsule::ClassRegistry.clear
25
+ class ClassRegistry
26
+ # Use Set for O(1) lookups instead of O(n) with Array#include?
27
+ @classes = Set.new
28
+
29
+ class << self
30
+ # Register a class that includes a StyleCapsule module
31
+ #
32
+ # @param klass [Class] The class to register
33
+ # @return [void]
34
+ def register(klass)
35
+ return if klass.nil?
36
+ return if klass.singleton_class?
37
+
38
+ # Only register classes with names (skip anonymous classes)
39
+ begin
40
+ name = klass.name
41
+ return if name.nil? || name.to_s.strip.empty?
42
+ rescue
43
+ # Skip classes that cause errors when calling name (e.g., ArgumentError, NoMethodError, NameError)
44
+ return
45
+ end
46
+
47
+ @classes.add(klass)
48
+ end
49
+
50
+ # Remove a class from the registry
51
+ #
52
+ # @param klass [Class] The class to unregister
53
+ # @return [void]
54
+ def unregister(klass)
55
+ @classes.delete(klass)
56
+ end
57
+
58
+ # Iterate over all registered classes
59
+ #
60
+ # @yield [Class] Each registered class
61
+ # @return [void]
62
+ def each(&block)
63
+ # Filter out classes that no longer exist or have been unloaded
64
+ # Use delete_if for Set (equivalent to reject! for Array)
65
+ @classes.delete_if do |klass|
66
+ # Check if class still exists and is valid
67
+ klass.name.nil? || klass.singleton_class?
68
+ rescue
69
+ # Class has been unloaded or causes errors - remove from registry
70
+ true
71
+ end
72
+
73
+ @classes.each(&block)
74
+ end
75
+
76
+ # Get all registered classes
77
+ #
78
+ # @return [Array<Class>] Array of registered classes
79
+ def all
80
+ # Filter out invalid classes
81
+ each.to_a
82
+ end
83
+
84
+ # Clear the registry
85
+ #
86
+ # Useful in development when classes are reloaded.
87
+ #
88
+ # @return [void]
89
+ def clear
90
+ @classes.clear
91
+ end
92
+
93
+ # Get the number of registered classes
94
+ #
95
+ # @return [Integer]
96
+ def count
97
+ each.count
98
+ end
99
+ end
100
+ end
101
+ end
@@ -89,6 +89,9 @@ module StyleCapsule
89
89
 
90
90
  # Use prepend to wrap view_template method
91
91
  base.prepend(ViewTemplateWrapper)
92
+
93
+ # Register class for Rails-friendly tracking
94
+ ClassRegistry.register(base)
92
95
  end
93
96
 
94
97
  module ClassMethods
@@ -21,34 +21,47 @@ module StyleCapsule
21
21
 
22
22
  # Find all Phlex components that use StyleCapsule
23
23
  #
24
+ # Uses ClassRegistry to find registered components (Rails-friendly, avoids expensive ObjectSpace scanning).
25
+ # Classes are automatically registered when they include StyleCapsule::Component.
26
+ #
24
27
  # @return [Array<Class>] Array of component classes
25
28
  def find_phlex_components
26
29
  return [] unless phlex_available?
27
30
 
28
31
  components = []
29
- ObjectSpace.each_object(Class) do |klass|
32
+
33
+ # Use the registry (Rails-friendly, avoids expensive ObjectSpace scanning)
34
+ ClassRegistry.each do |klass|
30
35
  if klass < Phlex::HTML && klass.included_modules.include?(StyleCapsule::Component)
31
36
  components << klass
32
37
  end
38
+ rescue
39
+ # Skip classes that cause errors (inheritance checks, etc.)
40
+ next
33
41
  end
42
+
34
43
  components
35
44
  end
36
45
 
37
46
  # Find all ViewComponent components that use StyleCapsule
38
47
  #
48
+ # Uses ClassRegistry to find registered components (Rails-friendly, avoids expensive ObjectSpace scanning).
49
+ # Classes are automatically registered when they include StyleCapsule::ViewComponent.
50
+ #
39
51
  # @return [Array<Class>] Array of component classes
40
52
  def find_view_components
41
53
  return [] unless view_component_available?
42
54
 
43
55
  components = []
56
+
44
57
  begin
45
- ObjectSpace.each_object(Class) do |klass|
58
+ # Use the registry (Rails-friendly, avoids expensive ObjectSpace scanning)
59
+ ClassRegistry.each do |klass|
46
60
  if klass < ViewComponent::Base && klass.included_modules.include?(StyleCapsule::ViewComponent)
47
61
  components << klass
48
62
  end
49
63
  rescue
50
- # Skip this class if checking inheritance triggers ViewComponent loading errors
51
- # (e.g., ViewComponent 2.83.0 has a bug with Gem::Version#to_f)
64
+ # Skip classes that cause errors (inheritance checks, etc.)
52
65
  next
53
66
  end
54
67
  rescue
@@ -56,6 +69,7 @@ module StyleCapsule
56
69
  # Silently skip ViewComponent components if there's an error
57
70
  # This allows the rake task to continue with Phlex components
58
71
  end
72
+
59
73
  components
60
74
  end
61
75
 
@@ -31,26 +31,16 @@ module StyleCapsule
31
31
  # This prevents memory leaks from stale cache entries during code reloading
32
32
  if Rails.env.development?
33
33
  config.to_prepare do
34
- # Clear CSS caches for all classes that include StyleCapsule modules
35
- # Skip singleton classes and handle errors gracefully
36
- ObjectSpace.each_object(Class) do |klass|
37
- # Skip singleton classes and classes without names (they can cause errors)
38
- # Singleton classes don't have proper names and can't be safely checked
39
- # Use fallback for blank? if ActiveSupport not available
40
- name = klass.name
41
- next if name.nil? || (name.respond_to?(:blank?) ? name.blank? : name.to_s.strip.empty?)
42
- next if klass.singleton_class?
43
-
44
- # Use method_defined? instead of respond_to? to avoid triggering delegation
45
- # that might cause errors with singleton classes or other edge cases
46
- begin
47
- if klass.method_defined?(:clear_css_cache, false) || klass.private_method_defined?(:clear_css_cache)
48
- klass.clear_css_cache
49
- end
50
- rescue
51
- # Skip classes that cause errors (singleton classes, delegation issues, etc.)
52
- next
34
+ # Use Rails-friendly class registry instead of ObjectSpace iteration
35
+ # This avoids issues with gems that override Class#name (e.g., Faker)
36
+ StyleCapsule::ClassRegistry.each do |klass|
37
+ # Clear CSS cache if the class has this method
38
+ if klass.method_defined?(:clear_css_cache, false) || klass.private_method_defined?(:clear_css_cache)
39
+ klass.clear_css_cache
53
40
  end
41
+ rescue
42
+ # Skip classes that cause errors (unloaded classes, etc.)
43
+ next
54
44
  end
55
45
 
56
46
  # Clear stylesheet manifest to allow re-registration during code reload
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StyleCapsule
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
@@ -89,6 +89,9 @@ module StyleCapsule
89
89
 
90
90
  # Use prepend to wrap call method
91
91
  base.prepend(CallWrapper)
92
+
93
+ # Register class for Rails-friendly tracking
94
+ ClassRegistry.register(base)
92
95
  end
93
96
 
94
97
  module ClassMethods
data/lib/style_capsule.rb CHANGED
@@ -92,6 +92,7 @@ module StyleCapsule
92
92
  require_relative "style_capsule/css_processor"
93
93
  require_relative "style_capsule/css_file_writer"
94
94
  require_relative "style_capsule/stylesheet_registry"
95
+ require_relative "style_capsule/class_registry"
95
96
  require_relative "style_capsule/component_styles_support"
96
97
  require_relative "style_capsule/component"
97
98
  require_relative "style_capsule/standalone_helper"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: style_capsule
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Makarov
@@ -261,6 +261,7 @@ files:
261
261
  - README.md
262
262
  - SECURITY.md
263
263
  - lib/style_capsule.rb
264
+ - lib/style_capsule/class_registry.rb
264
265
  - lib/style_capsule/component.rb
265
266
  - lib/style_capsule/component_builder.rb
266
267
  - lib/style_capsule/component_styles_support.rb