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
-
#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) ⇒ 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
#declarations ⇒ Array<Declaration>
Array of CSS property declarations
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def declarations @declarations end |
#id ⇒ Integer
The rule's position in the stylesheet (0-indexed)
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def id @id end |
#media_query_id ⇒ Integer?
ID of the MediaQuery this rule belongs to (nil if not in media query)
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def media_query_id @media_query_id end |
#nesting_style ⇒ Integer?
0=implicit, 1=explicit, nil=not nested
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def nesting_style @nesting_style end |
#parent_rule_id ⇒ Integer?
Parent rule ID for nested rules
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def parent_rule_id @parent_rule_id end |
#selector ⇒ String
The CSS selector (e.g., "body", ".class", "#id")
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 def selector @selector end |
#selector_list_id ⇒ Integer?
ID linking rules from same selector list (e.g., "h1, h2")
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 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
29 30 31 |
# File 'lib/cataract/rule.rb', line 29 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) ⇒ 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.
65 66 67 |
# File 'lib/cataract/rule.rb', line 65 def self.make(id:, selector:, declarations:, specificity: nil, parent_rule_id: nil, nesting_style: nil, selector_list_id: nil, media_query_id: nil) new(id, selector, declarations, specificity, parent_rule_id, nesting_style, selector_list_id, media_query_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.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/cataract/rule.rb', line 176 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.
106 107 108 |
# File 'lib/cataract/rule.rb', line 106 def at_rule? false end |
#at_rule_type?(_type) ⇒ Boolean
Check if this is a specific at-rule type.
114 115 116 |
# File 'lib/cataract/rule.rb', line 114 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.
155 156 157 158 159 160 161 |
# File 'lib/cataract/rule.rb', line 155 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.
133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/cataract/rule.rb', line 133 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
202 203 204 |
# File 'lib/cataract/rule.rb', line 202 def hash @_hash ||= [self.class, selector, ].hash end |
#selector? ⇒ Boolean
Check if this is a selector-based rule (vs an at-rule like @keyframes).
99 100 101 |
# File 'lib/cataract/rule.rb', line 99 def selector? true end |