Class: Coradoc::Query::Selector
- Inherits:
-
Object
- Object
- Coradoc::Query::Selector
- Defined in:
- lib/coradoc/query.rb
Overview
Selector parsing and matching
Supports CSS-like selectors for document querying:
-
Element type: ‘section`, `paragraph`, `table`
-
Class/level: ‘.level-2`, `.important`
-
ID: ‘#intro`, `#section-1`
-
Attributes: ‘[id=intro]`, `[role=example]`, `[level>1]`
-
Pseudo-classes: ‘:first-child`, `:last-child`, `:nth-child(2)`
-
Combinators: ‘>` (child), space (descendant)
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Returns the value of attribute attributes.
-
#classes ⇒ Object
readonly
Returns the value of attribute classes.
-
#element_type ⇒ Object
readonly
Returns the value of attribute element_type.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#pseudo_classes ⇒ Object
readonly
Returns the value of attribute pseudo_classes.
Class Method Summary collapse
-
.parse(selector) ⇒ Selector
Parse a selector string.
Instance Method Summary collapse
-
#initialize ⇒ Selector
constructor
A new instance of Selector.
-
#matches?(element) ⇒ Boolean
Check if an element matches this selector.
-
#matches_pseudo_classes?(element, siblings:, index:) ⇒ Boolean
Check pseudo-class conditions.
-
#parse(selector) ⇒ self
Parse a selector string into this object.
-
#universal? ⇒ Boolean
Check if selector is universal (*).
Constructor Details
#initialize ⇒ Selector
Returns a new instance of Selector.
48 49 50 51 52 53 54 |
# File 'lib/coradoc/query.rb', line 48 def initialize @element_type = nil @id = nil @classes = [] @attributes = {} @pseudo_classes = [] end |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Returns the value of attribute attributes.
38 39 40 |
# File 'lib/coradoc/query.rb', line 38 def attributes @attributes end |
#classes ⇒ Object (readonly)
Returns the value of attribute classes.
38 39 40 |
# File 'lib/coradoc/query.rb', line 38 def classes @classes end |
#element_type ⇒ Object (readonly)
Returns the value of attribute element_type.
38 39 40 |
# File 'lib/coradoc/query.rb', line 38 def element_type @element_type end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
38 39 40 |
# File 'lib/coradoc/query.rb', line 38 def id @id end |
#pseudo_classes ⇒ Object (readonly)
Returns the value of attribute pseudo_classes.
38 39 40 |
# File 'lib/coradoc/query.rb', line 38 def pseudo_classes @pseudo_classes end |
Class Method Details
.parse(selector) ⇒ Selector
Parse a selector string
44 45 46 |
# File 'lib/coradoc/query.rb', line 44 def self.parse(selector) new.parse(selector) end |
Instance Method Details
#matches?(element) ⇒ Boolean
Check if an element matches this selector
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/coradoc/query.rb', line 104 def matches?(element) return false unless element # Check element type return false if @element_type && !type_matches?(element) # Check ID return false if @id && element_id(element) != @id # Check classes/roles return false if @classes.any? && !classes_match?(element) # Check attributes return false if @attributes.any? && !attributes_match?(element) true end |
#matches_pseudo_classes?(element, siblings:, index:) ⇒ Boolean
Check pseudo-class conditions
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/coradoc/query.rb', line 128 def matches_pseudo_classes?(element, siblings:, index:) @pseudo_classes.all? do |pseudo| case pseudo[:name] when 'first-child' index.zero? when 'last-child' index == siblings.length - 1 when 'nth-child' n = pseudo[:argument].to_i index == n - 1 # 1-indexed in CSS when 'only-child' siblings.length == 1 when 'empty' empty_element?(element) else true # Unknown pseudo-classes pass end end end |
#parse(selector) ⇒ self
Parse a selector string into this object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/coradoc/query.rb', line 60 def parse(selector) @original = selector.to_s.strip return self if @original.empty? # Parse element type @original.sub!(/\A([a-z_][a-z0-9_-]*)/i) do |match| @element_type = match.downcase '' end # Parse ID @original.sub!(/#([a-z_][a-z0-9_-]*)/i) do @id = ::Regexp.last_match(1) '' end # Parse classes @original.gsub!(/\.([a-z_][a-z0-9_-]*)/i) do @classes << ::Regexp.last_match(1) '' end # Parse attributes @original.gsub!(/\[([^\]]+)\]/) do attr_expr = ::Regexp.last_match(1) parse_attribute(attr_expr) '' end # Parse pseudo-classes @original.gsub!(/:([a-z-]+)(?:\(([^)]+)\))?/i) do name = ::Regexp.last_match(1).downcase arg = ::Regexp.last_match(2) @pseudo_classes << { name: name, argument: arg } '' end self end |
#universal? ⇒ Boolean
Check if selector is universal (*)
151 152 153 |
# File 'lib/coradoc/query.rb', line 151 def universal? @element_type == '*' || @original == '*' end |