Class: Arbre::Html::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/arbre/html/querying.rb

Overview

Class to find tags from a given root tag / element based on a CSS-like query.

Constant Summary collapse

CSS_IDENTIFIER =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

/[-_a-z][-_a-z0-9]*/
CSS_SCAN =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%r[

  # Child node operator
  (>)?

  \s*

  (?:

    (\*)

    |

    # Tag name
    (#{CSS_IDENTIFIER})?

    # ID
    (?:\#(#{CSS_IDENTIFIER}))?

    # Class
    ((?:\.#{CSS_IDENTIFIER})+)?

    # Pseudo
    ((?::#{CSS_IDENTIFIER})+)?

    # Attributes
    ((?:\[.+?\])+)?

  )

]x

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ Query

Initialization



104
105
106
# File 'lib/arbre/html/querying.rb', line 104

def initialize(root)
  @root = root
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



108
109
110
# File 'lib/arbre/html/querying.rb', line 108

def root
  @root
end

Instance Method Details

#execute(query) ⇒ Object

Executes the given query.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/arbre/html/querying.rb', line 153

def execute(query)
  # Sanitize the query for processing.
  query = query.downcase.squeeze(' ')

  result = []

  selectors = query.split(',').map(&:strip).reject(&:blank?)

  selectors.map do |selector|
    tags = [ root ]

    # Run through all segments in the selector and process them one by one.
    selector.scan CSS_SCAN do |operator, all, tag, id, classes, pseudos, attributes|
      next unless all || tag || id || classes || pseudos || attributes

      classes = classes.split('.').reject(&:blank?) if classes
      pseudos = pseudos.split(':').reject(&:blank?) if pseudos

      # First process combinations of operator, all and id.
      tags = case operator
      when '>' then find_children(tags, tag, id, classes)
      else find_descendants(tags, tag, id, classes)
      end

      filter_by_pseudos tags, pseudos if pseudos
      filter_by_attributes tags, attributes if attributes
    end

    result.concat tags
  end

  # Convert to an element collection.
  ElementCollection.new(result)
end