Class: Cataract::Rule
- Inherits:
-
Struct
- Object
- Struct
- Cataract::Rule
- Defined in:
- lib/cataract/rule.rb,
lib/cataract/rule.rb
Overview
Rules are created by the parser and stored in Stylesheet objects. Each rule contains:
- An ID (position in the stylesheet)
- A CSS selector string
- An array of Declaration structs
- A specificity value (calculated lazily)
- Parent rule ID for nested rules (nil if top-level)
- Nesting style (0=implicit, 1=explicit, nil=not nested)
Media query information is stored separately in Stylesheet's media_index.
Instance Attribute Summary collapse
-
#conditional_group_id ⇒ Integer?
ID of the ConditionalGroup (@supports/@layer/@container/@scope) this rule belongs to (nil if not in one).
-
#declarations ⇒ Array<Declaration>
Array of CSS property declarations.
-
#id ⇒ Integer
The rule's position in the stylesheet (0-indexed).
-
#media_query_id ⇒ Integer?
ID of the MediaQuery this rule belongs to (nil if not in media query).
-
#nesting_style ⇒ Integer?
0=implicit, 1=explicit, nil=not nested.
-
#parent_rule_id ⇒ Integer?
Parent rule ID for nested rules.
-
#selector ⇒ String
The CSS selector (e.g., "body", ".class", "#id").
-
#selector_list_id ⇒ Integer?
ID linking rules from same selector list (e.g., "h1, h2").
-
#specificity ⇒ Integer
Get the CSS specificity value for this rule's selector.
Class Method Summary collapse
-
.make(id:, selector:, declarations:, specificity: nil, parent_rule_id: nil, nesting_style: nil, selector_list_id: nil, media_query_id: nil, conditional_group_id: nil) ⇒ Rule
Factory method for creating Rules with keyword arguments (for tests/readability).
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Compare rules for logical equality based on CSS semantics.
-
#at_rule? ⇒ Boolean
Check if this is an at-rule.
-
#at_rule_type?(_type) ⇒ Boolean
Check if this is a specific at-rule type.
-
#has_important?(property = nil) ⇒ Boolean
Check if this rule has any !important declarations, optionally for a specific property.
-
#has_property?(property, value = nil, prefix_match: false) ⇒ Boolean
Check if this rule has a declaration with the specified property and optional value.
-
#hash ⇒ Integer
Generate hash code for this rule.
-
#selector? ⇒ Boolean
Check if this is a selector-based rule (vs an at-rule like @keyframes).
Instance Attribute Details
#conditional_group_id ⇒ Integer?
ID of the ConditionalGroup (@supports/@layer/@container/@scope) this rule belongs to (nil if not in one)
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def conditional_group_id @conditional_group_id end |
#declarations ⇒ Array<Declaration>
Array of CSS property declarations
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def declarations @declarations end |
#id ⇒ Integer
The rule's position in the stylesheet (0-indexed)
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def id @id end |
#media_query_id ⇒ Integer?
ID of the MediaQuery this rule belongs to (nil if not in media query)
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def media_query_id @media_query_id end |
#nesting_style ⇒ Integer?
0=implicit, 1=explicit, nil=not nested
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def nesting_style @nesting_style end |
#parent_rule_id ⇒ Integer?
Parent rule ID for nested rules
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def parent_rule_id @parent_rule_id end |
#selector ⇒ String
The CSS selector (e.g., "body", ".class", "#id")
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def selector @selector end |
#selector_list_id ⇒ Integer?
ID linking rules from same selector list (e.g., "h1, h2")
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def selector_list_id @selector_list_id end |
#specificity ⇒ Integer
Get the CSS specificity value for this rule's selector.
Specificity is calculated lazily on first access and then cached. The calculation follows the CSS specification:
- Inline styles: not applicable to parsed stylesheets
- IDs: count of #id selectors
- Classes/attributes/pseudo-classes: count of .class, [attr], :pseudo
- Elements/pseudo-elements: count of element, ::pseudo
30 31 32 |
# File 'lib/cataract/rule.rb', line 30 def specificity @specificity end |
Class Method Details
.make(id:, selector:, declarations:, specificity: nil, parent_rule_id: nil, nesting_style: nil, selector_list_id: nil, media_query_id: nil, conditional_group_id: nil) ⇒ Rule
Factory method for creating Rules with keyword arguments (for tests/readability). C code and hot paths should use positional arguments directly via Rule.new.
69 70 71 |
# File 'lib/cataract/rule.rb', line 69 def self.make(id:, selector:, declarations:, specificity: nil, parent_rule_id: nil, nesting_style: nil, selector_list_id: nil, media_query_id: nil, conditional_group_id: nil) new(id, selector, declarations, specificity, parent_rule_id, nesting_style, selector_list_id, media_query_id, conditional_group_id) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Compare rules for logical equality based on CSS semantics.
Two rules are equal if they have the same selector and declarations.
Shorthand properties are expanded before comparison, so
margin: 10px equals margin-top: 10px; margin-right: 10px; ...
Internal implementation details (id, specificity) are not considered since they don't affect the CSS semantics.
Can also compare against a CSS string, which is parsed and compared.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/cataract/rule.rb', line 183 def ==(other) case other when Rule return false unless selector == other.selector == other. when String # Parse CSS string and compare to first rule parsed = Cataract.parse_css(other) return false unless parsed.rules.size == 1 self == parsed.rules.first else false end end |
#at_rule? ⇒ Boolean
Check if this is an at-rule.
113 114 115 |
# File 'lib/cataract/rule.rb', line 113 def at_rule? false end |
#at_rule_type?(_type) ⇒ Boolean
Check if this is a specific at-rule type.
121 122 123 |
# File 'lib/cataract/rule.rb', line 121 def at_rule_type?(_type) false end |
#has_important?(property = nil) ⇒ Boolean
Check if this rule has any !important declarations, optionally for a specific property.
162 163 164 165 166 167 168 |
# File 'lib/cataract/rule.rb', line 162 def has_important?(property = nil) if property declarations.any? { |d| d.property == property && d.important } else declarations.any?(&:important) end end |
#has_property?(property, value = nil, prefix_match: false) ⇒ Boolean
Check if this rule has a declaration with the specified property and optional value.
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/cataract/rule.rb', line 140 def has_property?(property, value = nil, prefix_match: false) declarations.any? do |decl| property_matches = if prefix_match decl.property.start_with?(property) else decl.property == property end value_matches = value.nil? || decl.value == value property_matches && value_matches end end |
#hash ⇒ Integer
Generate hash code for this rule.
Hash is based on selector and expanded declarations to match the equality semantics. This allows rules to be used as Hash keys or in Sets correctly.
rubocop:disable Naming/MemoizedInstanceVariableName
209 210 211 |
# File 'lib/cataract/rule.rb', line 209 def hash @_hash ||= [self.class, selector, ].hash end |
#selector? ⇒ Boolean
Check if this is a selector-based rule (vs an at-rule like @keyframes).
106 107 108 |
# File 'lib/cataract/rule.rb', line 106 def selector? true end |