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, adapter:) ⇒ Selector

Initialize a Selector.

Parameters:



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

def initialize(
  goto_scope: nil,
  relationship: nil,
  rest: nil,
  basic_selector: nil,
  position: nil,
  pseudo_class: nil,
  pseudo_selector: nil,
  adapter:
)
  @goto_scope = goto_scope
  @relationship = relationship
  @rest = rest
  @basic_selector = basic_selector
  @position = position
  @pseudo_class = pseudo_class
  @pseudo_selector = pseudo_selector
  @adapter = adapter
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:



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

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
  @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.



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
103
104
105
# File 'lib/node_query/compiler/selector.rb', line 68

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, @adapter) do |child_node|
        if match?(child_node, child_node)
          nodes << child_node
          break if options[:stop_at_first_match]
        end
      end
    else
      @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



107
108
109
110
111
112
113
114
115
116
# File 'lib/node_query/compiler/selector.rb', line 107

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