class Capybara::Selector::RegexpDisassembler
@api private
Public Class Methods
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 9 def initialize(regexp) @regexp = regexp end
Public Instance Methods
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 13 def alternated_substrings @alternated_substrings ||= begin or_strings = process(alternation: true) remove_or_covered(or_strings) or_strings.any?(&:empty?) ? [] : or_strings end end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 21 def substrings @substrings ||= begin strs = process(alternation: false).first remove_and_covered(strs) end end
Private Instance Methods
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 81 def collapse(strs) strs.map do |substrings| substrings.slice_before(&:nil?).map(&:join).reject(&:empty?).uniq end end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 68 def combine(strs) suffixes = [[]] strs.reverse_each do |str| if str.is_a? Set prefixes = str.flat_map { |s| combine(s) } suffixes = prefixes.product(suffixes).map { |pair| pair.flatten(1) } else suffixes.each { |arr| arr.unshift str } end end suffixes end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 87 def extract_strings(expression, alternation: false) Expression.new(expression).extract_strings(alternation) end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 61 def process(alternation:) strs = extract_strings(Regexp::Parser.parse(@regexp), alternation: alternation) strs = collapse(combine(strs).map(&:flatten)) strs.each { |str| str.map!(&:upcase) } if @regexp.casefold? strs end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 30 def remove_and_covered(strings) # delete_if is documented to modify the array after every block iteration - this doesn't appear to be true # uniq the strings to prevent identical strings from removing each other strings.uniq! # If we have "ab" and "abcd" required - only need to check for "abcd" strings.delete_if do |sub_string| strings.any? do |cover_string| next if sub_string.equal? cover_string cover_string.include?(sub_string) end end end
Source
# File lib/capybara/selector/regexp_disassembler.rb, line 45 def remove_or_covered(or_series) # If we are going to match `("a" and "b") or ("ade" and "bce")` it only makes sense to match ("a" and "b") # Ensure minimum sets of strings are being or'd or_series.each { |strs| remove_and_covered(strs) } # Remove any of the alternated string series that fully contain any other string series or_series.delete_if do |and_strs| or_series.any? do |and_strs2| next if and_strs.equal? and_strs2 remove_and_covered(and_strs + and_strs2) == and_strs end end end