1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
# frozen_string_literal: true
module XPath
module DSL
def current
Expression.new(:this_node)
end
def descendant(*expressions)
Expression.new(:descendant, current, expressions)
end
def child(*expressions)
Expression.new(:child, current, expressions)
end
def axis(name, *element_names)
Expression.new(:axis, current, name, element_names)
end
def anywhere(*expressions)
Expression.new(:anywhere, expressions)
end
def attr(expression)
Expression.new(:attribute, current, expression)
end
def text
Expression.new(:text, current)
end
def css(selector)
Expression.new(:css, current, Literal.new(selector))
end
def function(name, *arguments)
Expression.new(:function, name, *arguments)
end
def method(name, *arguments)
Expression.new(:function, name, current, *arguments)
end
def where(expression)
if expression
Expression.new(:where, current, expression)
else
current
end
end
alias_method :[], :where
def is(expression)
Expression.new(:is, current, expression)
end
def binary_operator(name, rhs)
Expression.new(:binary_operator, name, current, rhs)
end
def union(*expressions)
Union.new(*[self, expressions].flatten)
end
alias_method :+, :union
def last
function(:last)
end
def position
function(:position)
end
METHODS = [
# node set
:count, :id, :local_name, :namespace_uri,
# string
:string, :concat, :starts_with, :contains, :substring_before,
:substring_after, :substring, :string_length, :normalize_space,
:translate,
# boolean
:boolean, :not, :true, :false, :lang,
# number
:number, :sum, :floor, :ceiling, :round
].freeze
METHODS.each do |key|
name = key.to_s.tr('_', '-').to_sym
define_method key do |*args|
method(name, *args)
end
end
def qname
method(:name)
end
alias_method :inverse, :not
alias_method :~, :not
alias_method :!, :not
alias_method :normalize, :normalize_space
alias_method :n, :normalize_space
OPERATORS = [
%i[equals = ==],
%i[or or |],
%i[and and &],
%i[not_equals != !=],
%i[lte <= <=],
%i[lt < <],
%i[gte >= >=],
%i[gt > >],
%i[plus +],
%i[minus -],
%i[multiply * *],
%i[divide div /],
%i[mod mod %]
].freeze
OPERATORS.each do |(name, operator, alias_name)|
define_method name do |rhs|
binary_operator(operator, rhs)
end
alias_method alias_name, name if alias_name
end
AXES = %i[
ancestor ancestor_or_self attribute descendant_or_self
following following_sibling namespace parent preceding
preceding_sibling self
].freeze
AXES.each do |key|
name = key.to_s.tr('_', '-').to_sym
define_method key do |*element_names|
axis(name, *element_names)
end
end
alias_method :self_axis, :self
def ends_with(suffix)
function(:substring, current, function(:'string-length', current).minus(function(:'string-length', suffix)).plus(1)) == suffix
end
def contains_word(word)
function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ")
end
UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'
LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'
def lowercase
method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS)
end
def uppercase
method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS)
end
def one_of(*expressions)
expressions.map { |e| current.equals(e) }.reduce(:or)
end
def next_sibling(*expressions)
axis(:"following-sibling")[1].axis(:self, *expressions)
end
def previous_sibling(*expressions)
axis(:"preceding-sibling")[1].axis(:self, *expressions)
end
end
end
|