cataract 0.2.1 → 0.2.3

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: a1c4727f2f1b3c3aafa117ca105ee0d55a6d6f33b0fed789533af10c24173918
4
- data.tar.gz: 86c0e96b1a953fb817fa235517e00215b4b363baea7d1225c5fcb2b9643b29c9
3
+ metadata.gz: a5945042f40d16bf57bcc0c5479221959e231eb2742c51019f907d1d3ab1110c
4
+ data.tar.gz: 92734f20818a3c0e94b8f7adaccf5e6a37d65325223f0dbbafae2efc8ddc11d8
5
5
  SHA512:
6
- metadata.gz: 7282bde75fb5cd81ad2b7f2d7134a6fde2941a8f5320a4de2d463114d25bfc709e80f1639e9479cb69b7f22d685d203a7097fa0cf8c2e952041b733420991080
7
- data.tar.gz: f8af1d50b389d64c36c5138f431b5b09f95ec3ca8f68b6c342ec280e7e1c84a8fca95ec6c95a81d97f9bced8d0f295acfbf2849ca47939e16cbf1b408544cdbe
6
+ metadata.gz: b1c8dc3e693f042549bdaf2561599c76cf2f5940809f3c5005b17ee90a04cab9a99f35598f55f9d422a3f00ab04d493c76a0f291ce636711c9dabcb2879aceb2
7
+ data.tar.gz: 6d239fd54239b01ec42215296964d0140e40ae1841eae2d4af12e0982d5478ad2ee49c5f6628f067ef5168bef5845f07780e63fc6e6be4875c06c21f8f0afb20
@@ -32,7 +32,7 @@ jobs:
32
32
  uses: actions/cache@v4
33
33
  with:
34
34
  path: .lint-passed
35
- key: lint-${{ hashFiles('ext/**/*.c', 'ext/**/*.h', '.clang-tidy', 'Gemfile') }}
35
+ key: lint-${{ hashFiles('ext/**/*.c', 'ext/**/*.h', '.clang-tidy', 'Gemfile', '.github/workflows/*.yml', 'cataract.gemspec', 'Rakefile') }}
36
36
 
37
37
  - name: Install clang-tidy
38
38
  if: steps.lint-cache.outputs.cache-hit != 'true'
data/.rubocop.yml CHANGED
@@ -171,5 +171,7 @@ Cataract/BanAssertIncludes:
171
171
  Include:
172
172
  - 'test/**/*'
173
173
  Exclude:
174
+ - 'test/color/**/*.rb'
174
175
  - 'test/test_benchmark_doc_generator.rb'
176
+ - 'test/test_speedup_calculator.rb'
175
177
  - 'test/support/**/*' # Support files define assert_contains which uses assert_includes internally
data/BENCHMARKS.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # Performance Benchmarks
6
6
 
7
- Performance comparison between Cataract's C extension and pure Ruby implementations, with css_parser as a reference.
7
+ Performance comparison between Cataract's C extension and pure Ruby implementations.
8
8
 
9
9
  ## Test Environment
10
10
 
@@ -18,18 +18,19 @@ Performance comparison between Cataract's C extension and pure Ruby implementati
18
18
 
19
19
  Time to parse CSS into internal data structures
20
20
 
21
- | Test Case | Native | Pure (no YJIT) | Pure (YJIT) | css_parser (no YJIT) | css_parser (YJIT) |
22
- |-----------|--------|----------------|-------------|----------------------|-------------------|
23
- | Small CSS (64 lines, 1.0KB) | 62.47K i/s | 3.59K i/s | 15.67K i/s | 4.73K i/s | 6.17K i/s |
24
- | Medium CSS with @media (139 lines, 1.6KB) | 39.7K i/s | 2.05K i/s | 8.64K i/s | 2.76K i/s | 3.52K i/s |
21
+ | Test Case | Native | Pure (no YJIT) | Pure (YJIT) |
22
+ |-----------|--------|----------------|-------------|
23
+ | Small CSS (64 lines, 1.0KB) | 36.46K i/s | 3.46K i/s | 14.1K i/s |
24
+ | Medium CSS with @media (139 lines, 1.6KB) | 37.11K i/s | 2.1K i/s | 9.26K i/s |
25
+ | Selector lists (3500 lines, 62.5KB, 500 lists) | 447.6 i/s | 57.9 i/s | 212.5 i/s |
25
26
 
26
27
  ### Speedups
27
28
 
28
29
  | Comparison | Speedup |
29
30
  |------------|---------|
30
- | Native vs Pure (no YJIT) | 18.4x faster (avg) |
31
- | Native vs Pure (YJIT) | 4.2x faster (avg) |
32
- | YJIT impact on Pure Ruby | 4.31x faster (avg) |
31
+ | Native vs Pure (no YJIT) | 12.14x faster (avg) |
32
+ | Native vs Pure (YJIT) | 2.89x faster (avg) |
33
+ | YJIT impact on Pure Ruby | 4.14x faster (avg) |
33
34
 
34
35
  ---
35
36
 
@@ -37,18 +38,21 @@ Time to parse CSS into internal data structures
37
38
 
38
39
  Time to convert parsed CSS back to string format
39
40
 
40
- | Test Case | Native | Pure (no YJIT) | Pure (YJIT) | css_parser (no YJIT) | css_parser (YJIT) |
41
- |-----------|--------|----------------|-------------|----------------------|-------------------|
42
- | Full Serialization (Bootstrap CSS - 191KB) | 1.77K i/s | 444.3 i/s | 676.3 i/s | 37.1 i/s | 35.9 i/s |
43
- | Media Type Filtering (print only) | 282.58K i/s | 114.27K i/s | 155.82K i/s | 2.67K i/s | 4.03K i/s |
41
+ | Test Case | Native | Pure (no YJIT) | Pure (YJIT) |
42
+ |-----------|--------|----------------|-------------|
43
+ | to_s (Bootstrap - 191KB) | 1.16K i/s | 34.9 i/s | 49.7 i/s |
44
+ | to_s (Compact utilities - 2.9KB) | 1.16K i/s | 34.9 i/s | 49.7 i/s |
45
+ | to_formatted_s (Nested CSS - 1.3KB) | 158.75K i/s | 63.62K i/s | 114.79K i/s |
46
+ | to_s with selector_lists (3.4KB) | 17.95K i/s | 1.43K i/s | 1.99K i/s |
47
+ | Media filtering (Bootstrap print only) | 235.05K i/s | 98.95K i/s | 149.3K i/s |
44
48
 
45
49
  ### Speedups
46
50
 
47
51
  | Comparison | Speedup |
48
52
  |------------|---------|
49
- | Native vs Pure (no YJIT) | 3.23x faster (avg) |
50
- | Native vs Pure (YJIT) | 1.82x faster (avg) |
51
- | YJIT impact on Pure Ruby | 1.36x faster (avg) |
53
+ | Native vs Pure (no YJIT) | 10.97x faster (avg) |
54
+ | Native vs Pure (YJIT) | 7.56x faster (avg) |
55
+ | YJIT impact on Pure Ruby | 1.57x faster (avg) |
52
56
 
53
57
  ---
54
58
 
@@ -56,22 +60,22 @@ Time to convert parsed CSS back to string format
56
60
 
57
61
  Time to calculate CSS selector specificity values
58
62
 
59
- | Test Case | Native | Pure (no YJIT) | Pure (YJIT) | css_parser (no YJIT) | css_parser (YJIT) |
60
- |-----------|--------|----------------|-------------|----------------------|-------------------|
61
- | Simple Selectors | 7.35M i/s | 506.04K i/s | 2.59M i/s | 357.72K i/s | 353.42K i/s |
62
- | Compound Selectors | 6.36M i/s | 184.96K i/s | 406.99K i/s | 216.59K i/s | 214.86K i/s |
63
- | Combinators | 5.04M i/s | 146.91K i/s | 252.94K i/s | 185.44K i/s | 183.71K i/s |
64
- | Pseudo-classes & Pseudo-elements | 5.1M i/s | 116.46K i/s | 197.06K i/s | 113.05K i/s | 113.99K i/s |
65
- | :not() Pseudo-class (CSS3) | 3.23M i/s | 102.63K i/s | 161.55K i/s | 144.04K i/s | 144.53K i/s |
66
- | Complex Real-world Selectors | 4.01M i/s | 52.03K i/s | 77.65K i/s | 83.91K i/s | 82.03K i/s |
63
+ | Test Case | Native | Pure (no YJIT) | Pure (YJIT) |
64
+ |-----------|--------|----------------|-------------|
65
+ | Simple Selectors | 8.42M i/s | 508.29K i/s | 2.6M i/s |
66
+ | Compound Selectors | 6.6M i/s | 186.16K i/s | 400.7K i/s |
67
+ | Combinators | 5.21M i/s | 147.76K i/s | 255.26K i/s |
68
+ | Pseudo-classes & Pseudo-elements | 5.39M i/s | 117.25K i/s | 196.91K i/s |
69
+ | :not() Pseudo-class (CSS3) | 3.48M i/s | 103.11K i/s | 164.66K i/s |
70
+ | Complex Real-world Selectors | 4.05M i/s | 52.17K i/s | 78.28K i/s |
67
71
 
68
72
  ### Speedups
69
73
 
70
74
  | Comparison | Speedup |
71
75
  |------------|---------|
72
- | Native vs Pure (no YJIT) | 39.27x faster (avg) |
73
- | Native vs Pure (YJIT) | 8.43x faster (avg) |
74
- | YJIT impact on Pure Ruby | 3.32x faster (avg) |
76
+ | Native vs Pure (no YJIT) | 40.75x faster (avg) |
77
+ | Native vs Pure (YJIT) | 23.38x faster (avg) |
78
+ | YJIT impact on Pure Ruby | 2.29x faster (avg) |
75
79
 
76
80
  ---
77
81
 
@@ -79,22 +83,22 @@ Time to calculate CSS selector specificity values
79
83
 
80
84
  Time to flatten multiple CSS rule sets with same selector
81
85
 
82
- | Test Case | Native | Pure (no YJIT) | Pure (YJIT) | css_parser (no YJIT) | css_parser (YJIT) |
83
- |-----------|--------|----------------|-------------|----------------------|-------------------|
84
- | No shorthand properties (large) | 21.34K i/s | 3.11K i/s | 5.23K i/s | 1.58K i/s | 2.3K i/s |
85
- | Simple properties | 158.81K i/s | 75.72K i/s | 102.44K i/s | 28.29K i/s | 40.72K i/s |
86
- | Cascade with specificity | 204.11K i/s | 77.93K i/s | 108.77K i/s | 31.92K i/s | 46.39K i/s |
87
- | Important declarations | 203.43K i/s | 77.88K i/s | 109.38K i/s | 31.25K i/s | 45.25K i/s |
88
- | Shorthand expansion | 21.34K i/s | 3.11K i/s | 5.23K i/s | 1.58K i/s | 2.3K i/s |
89
- | Complex merging | 30.94K i/s | 16.09K i/s | 21.57K i/s | 11.6K i/s | 16.63K i/s |
86
+ | Test Case | Native | Pure (no YJIT) | Pure (YJIT) |
87
+ |-----------|--------|----------------|-------------|
88
+ | No shorthand properties (large) | 20.74K i/s | 3.15K i/s | 5.73K i/s |
89
+ | Simple properties | 155.01K i/s | 73.1K i/s | 99.95K i/s |
90
+ | Cascade with specificity | 194.63K i/s | 74.22K i/s | 104.8K i/s |
91
+ | Important declarations | 195.45K i/s | 72.82K i/s | 105.65K i/s |
92
+ | Shorthand expansion | 20.74K i/s | 3.15K i/s | 5.73K i/s |
93
+ | Complex flattening | 31.19K i/s | 15.81K i/s | 21.52K i/s |
90
94
 
91
95
  ### Speedups
92
96
 
93
97
  | Comparison | Speedup |
94
98
  |------------|---------|
95
- | Native vs Pure (no YJIT) | 3.03x faster (avg) |
96
- | Native vs Pure (YJIT) | 1.72x faster (avg) |
97
- | YJIT impact on Pure Ruby | 1.38x faster (avg) |
99
+ | Native vs Pure (no YJIT) | 3.01x faster (avg) |
100
+ | Native vs Pure (YJIT) | 1.97x faster (avg) |
101
+ | YJIT impact on Pure Ruby | 1.47x faster (avg) |
98
102
 
99
103
  ---
100
104
 
@@ -118,5 +122,4 @@ rake benchmark:generate_docs
118
122
 
119
123
  - Benchmarks use benchmark-ips with 1-2s warmup and 2-5s measurement periods
120
124
  - Measurements show median iterations per second (i/s)
121
- - css_parser gem is included for reference comparison
122
125
  - YJIT is enabled/disabled per subprocess for accurate comparison
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## [ Unreleased ]
2
+
3
+ ## [0.2.3 - 2025-11-18]
4
+ - Pure Parser: Bugs with url()
5
+
6
+ ## [0.2.2 - 2025-11-18]
7
+
8
+ - Feature: Selector list tracking - parser preserves comma-separated selector groupings (e.g., `h1, h2, h3`) through parse/flatten/serialize cycle
9
+ - Feature: Intelligent selector list serialization - automatically detects divergence during cascade and groups only matching rules
10
+ - Feature: Formatted CSS output with configurable line wrapping (`to_s(formatted: true, max_line_length: 80)`)
11
+ - Feature: Custom property (CSS variable) support - `Stylesheet#custom_properties` returns custom properties organized by media context
12
+ - Fix: Custom properties now preserve case-sensitivity per CSS spec (`--Color` vs `--color` are distinct)
13
+ - Fix: Custom properties support UTF-8 encoding for Unicode characters
14
+ - Fix: Property matching now supports prefix matching for vendor-prefixed properties
15
+ - Performance: Flatten operation optimized with manual iteration for selector list grouping
16
+
1
17
  ## [0.2.1] - 2025-11-14
2
18
 
3
19
  - Fix serializer bug related to media queries
data/README.md CHANGED
@@ -134,6 +134,12 @@ sheet.with_specificity(100..).each do |rule|
134
134
  puts "High specificity: #{rule.selector} (#{rule.specificity})"
135
135
  end
136
136
 
137
+ # Filter by property (returns chainable scope)
138
+ sheet.with_property('margin') # Exact match: finds only 'margin' property
139
+ sheet.with_property('margin', prefix_match: true) # Prefix match: finds margin, margin-top, margin-left, etc.
140
+ sheet.with_property('background', prefix_match: true) # Finds ALL background-* properties
141
+ sheet.with_property('margin', '10px') # Filter by value too
142
+
137
143
  # Chain filters together
138
144
  sheet.with_media(:screen)
139
145
  .with_specificity(50..200)
@@ -141,9 +147,9 @@ sheet.with_media(:screen)
141
147
  .map(&:selector)
142
148
  # => ["#header .nav", ".sidebar > ul li"]
143
149
 
144
- # Find all rules with a specific property
145
- sheet.select(&:selector?).select do |rule|
146
- rule.declarations.any? { |d| d.property == 'color' }
150
+ # Find all rules with any margin-related property
151
+ sheet.with_property('margin', prefix_match: true).each do |rule|
152
+ puts "#{rule.selector} uses margin"
147
153
  end
148
154
 
149
155
  # Find high-specificity selectors (potential refactoring targets)