Class: NodeQuery::Compiler::Selector

Inherits:
Object
  • Object
show all
Defined in:
lib/node_query/compiler/selector.rb

Overview

Selector used to match nodes, it combines by node type and/or attribute list, plus index or has expression.

Instance Method Summary collapse

Constructor Details

#initialize(goto_scope: nil, relationship: nil, rest: nil, basic_selector: nil, position: nil, pseudo_class: nil, pseudo_selector: nil) ⇒ Selector

Initialize a Selector.

Parameters:



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/node_query/compiler/selector.rb', line 15

def initialize(
  goto_scope: nil,
  relationship: nil,
  rest: nil,
  basic_selector: nil,
  position: nil,
  pseudo_class: nil,
  pseudo_selector: nil
)
  @goto_scope = goto_scope
  @relationship = relationship
  @rest = rest
  @basic_selector = basic_selector
  @position = position
  @pseudo_class = pseudo_class
  @pseudo_selector = pseudo_selector
end

Instance Method Details

#match?(node, base_node, operator = "=") ⇒ Boolean

Check if node matches the selector.

Parameters:

  • node (Node)

    the node

  • base_node (Node)

    the base node for evaluated node

Returns:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/node_query/compiler/selector.rb', line 36

def match?(node, base_node, operator = "=")
  if node.is_a?(::Array)
    case operator
    when "not_includes"
      return node.none? { |child_node| match?(child_node, base_node) }
    when "includes"
      return node.any? { |child_node| match?(child_node, base_node) }
    else
      return false
    end
  end
  NodeQuery.adapter.is_node?(node) && (!@basic_selector || (operator == "!=" ? !@basic_selector.match?(
    node,
    base_node
  ) : @basic_selector.match?(node, base_node))) && match_pseudo_class?(node)
end

#query_nodes(node, options = {}) ⇒ Array<Node>

Query nodes by the selector.

  • If relationship is nil, it will match in all recursive child nodes and return matching nodes.

  • If relationship is decendant, it will match in all recursive child nodes.

  • If relationship is child, it will match in direct child nodes.

  • If relationship is next sibling, it try to match next sibling node.

  • If relationship is subsequent sibling, it will match in all sibling nodes.

Parameters:

  • node (Node)

    node to match

  • options (Hash) (defaults to: {})

    if query the current node

Options Hash (options):

  • :including_self (boolean)

    if query the current node, default is ture

  • :stop_at_first_match (boolean)

    if stop at first match, default is false

  • :recursive (boolean)

    if recursively query child nodes, default is true

Returns:

  • (Array<Node>)

    matching nodes.



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
99
100
101
102
# File 'lib/node_query/compiler/selector.rb', line 65

def query_nodes(node, options = {})
  options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
  return find_nodes_by_relationship(node) if @relationship

  if node.is_a?(::Array)
    return node.flat_map { |child_node| query_nodes(child_node) }
  end

  return find_nodes_by_goto_scope(node) if @goto_scope

  if options[:including_self] && !options[:recursive]
    return match?(node, node) ? [node] : []
  end

  nodes = []
  if options[:including_self] && match?(node, node)
    nodes << node
    return nodes if options[:stop_at_first_match]
  end
  if @basic_selector
    if options[:recursive]
      NodeQuery::Helper.handle_recursive_child(node) do |child_node|
        if match?(child_node, child_node)
          nodes << child_node
          break if options[:stop_at_first_match]
        end
      end
    else
      NodeQuery.adapter.get_children(node).each do |child_node|
        if match?(child_node, child_node)
          nodes << child_node
          break if options[:stop_at_first_match]
        end
      end
    end
  end
  filter_by_position(nodes)
end

#to_sObject



104
105
106
107
108
109
110
111
112
113
# File 'lib/node_query/compiler/selector.rb', line 104

def to_s
  result = []
  result << "#{@goto_scope} " if @goto_scope
  result << "#{@relationship} " if @relationship
  result << @rest.to_s if @rest
  result << @basic_selector.to_s if @basic_selector
  result << ":#{@position}" if @position
  result << ":#{@pseudo_class}(#{@pseudo_selector})" if @pseudo_class
  result.join('')
end