class Paru::Selector

A Selector models a relationship between Pandoc AST nodes, such as parent-child or sibling. Selectors in paru are like CSS selectors, but more limited because the Pandoc AST is quite simple.

Given a selector expression, Selector determines if a node complies with that selector expression or not.

Constants

ANY_SELECTOR

Pseudo selector to select any inline and block node

CLASS

Improved CSS class selector taken from stackoverflow.com/questions/448981/which-characters-are-valid-in-css-class-names-selectors/449000#449000

DISTANCE
OPERATOR
OTHER_TYPE
PSEUDO_SELECTORS

All pseudo selectors

RELATION
RELATIONS
S
SELECTOR
TYPE

Public Class Methods

new(selector) click to toggle source

Create a new Selector based on the selector string

@param selector [String] the selector string

# File lib/paru/selector.rb, line 44
def initialize(selector)
    @type = 'Unknown'
    @relations = []
    parse selector
end

Public Instance Methods

matches?(node, filtered_nodes) click to toggle source

Does node get selected by this Selector in the context of the already filtered nodes?

@param node [Node] the node to check against this Selector @param filtered_nodes [Array<Node>] the context of filtered nodes to take

into account as well

@return [Boolean] True if the node in the context of the

filtered_nodes is selected by this Selector
# File lib/paru/selector.rb, line 59
def matches? node, filtered_nodes
    case @type 
    when ANY_SELECTOR
      Paru::PANDOC_TYPES.include? node.type
    else
      node.type == @type and 
          @classes.all? {|c| node.has_class? c } and    
          @relations.all? {|r| r.matches? node, filtered_nodes}
    end
end

Private Instance Methods

continue_parsing?(parts) click to toggle source
# File lib/paru/selector.rb, line 139
def continue_parsing?(parts)
    not parts.nil? and not parts[:relations].nil?
end
expect(parts, part) click to toggle source
# File lib/paru/selector.rb, line 104
def expect(parts, part)
    raise SelectorParseError.new "Expected #{part}" if parts[part].nil?
    parts[part]
end
expect_integer(parts, part) click to toggle source
# File lib/paru/selector.rb, line 129
def expect_integer(parts, part)
    if parts[part].nil?
        number = 0
    else
        number = parts[part].to_i
        raise SelectorParseError.new "Expected a positive #{part}, got '#{parts[part]}' instead" if number <= 0
    end
    number
end
expect_match(regexp, string) click to toggle source
# File lib/paru/selector.rb, line 109
def expect_match(regexp, string)
    match = regexp.match string
    raise SelectorParseError.new "Unable to parse '#{string}'" if match.nil?
    match
end
expect_pandoc_other_type(parts) click to toggle source
# File lib/paru/selector.rb, line 122
def expect_pandoc_other_type(parts)
    type = expect parts, :other_name
    classes = parts[:other_classes].split('.').select {|c| not c.empty?} if not parts[:other_classes].nil?
    raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
    [type, classes]
end
expect_pandoc_type(parts) click to toggle source
# File lib/paru/selector.rb, line 115
def expect_pandoc_type(parts)
    type = expect parts, :name
    classes = parts[:classes].split(".").select {|c| not c.empty?} if not parts[:classes].nil?
    raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
    [type, classes]
end
is_pandoc_type(type) click to toggle source

Is type actually a Pandoc AST node type?

# File lib/paru/selector.rb, line 100
def is_pandoc_type(type)
  Paru::PANDOC_TYPES.concat(PSEUDO_SELECTORS).include? type
end
parse(selector_string) click to toggle source

Parse the selector_string to construct this Selector

# File lib/paru/selector.rb, line 84
def parse(selector_string)
    partial_match = expect_match SELECTOR, selector_string
    @type, @classes = expect_pandoc_type partial_match

    while continue_parsing? partial_match
        operator = expect partial_match, :operator
        distance = expect_integer partial_match, :distance 
        type, classes = expect_pandoc_other_type partial_match

        @relations.push Relation.new(operator, distance, type, classes)

        partial_match = rest partial_match
    end
end
rest(parts) click to toggle source
# File lib/paru/selector.rb, line 143
def rest(parts)
    rest_string = parts[:relations].slice 0, parts[:relations].size - parts[:relation].size
    RELATIONS.match rest_string
end