Class: Regexp::Expression::Subexpression

Inherits:
Base
  • Object
show all
Includes:
Enumerable
Defined in:
lib/regexp_parser/expression/subexpression.rb,
lib/regexp_parser/expression/methods/traverse.rb,
lib/regexp_parser/expression/methods/strfregexp.rb,
lib/regexp_parser/expression/methods/match_length.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#ascii_classes?, #case_insensitive?, #default_classes?, #free_spacing?, #greedy?, #match, #match?, #multiline?, #possessive?, #quantify, #quantity, #reluctant?, #repetitions, #strfregexp, #to_re, #unicode_classes?, #unquantified_clone

Methods included from Shared

#==, #base_length, #coded_offset, #ends_at, #full_length, #human_name, included, #inspect, #is?, #negated?, #negative?, #nesting_level=, #offset, #one_of?, #optional?, #parts, #pre_quantifier_decoration, #pretty_print, #pretty_print_instance_variables, #quantified?, #quantifier=, #quantifier_affix, #starts_at, #to_s, #token_class, #type?

Constructor Details

#initialize(token, options = {}) ⇒ Subexpression

Returns a new instance of Subexpression.



7
8
9
10
# File 'lib/regexp_parser/expression/subexpression.rb', line 7

def initialize(token, options = {})
  self.expressions = []
  super
end

Instance Attribute Details

#expressionsObject

Returns the value of attribute expressions.



5
6
7
# File 'lib/regexp_parser/expression/subexpression.rb', line 5

def expressions
  @expressions
end

Instance Method Details

#<<(exp) ⇒ Object



20
21
22
23
# File 'lib/regexp_parser/expression/subexpression.rb', line 20

def <<(exp)
  exp.parent = self
  expressions << exp
end

#dig(*indices) ⇒ Object



33
34
35
36
37
# File 'lib/regexp_parser/expression/subexpression.rb', line 33

def dig(*indices)
  exp = self
  indices.each { |idx| exp = exp.nil? || exp.terminal? ? nil : exp[idx] }
  exp
end

#each_expression(include_self = false, &block) ⇒ Object

Traverses the expression, passing each recursive child to the given block. If the block takes two arguments, the indices of the children within their parents are also passed to it.



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/regexp_parser/expression/methods/traverse.rb', line 8

def each_expression(include_self = false, &block)
  return enum_for(__method__, include_self) unless block

  if block.arity == 1
    block.call(self) if include_self
    each_expression_without_index(&block)
  else
    block.call(self, 0) if include_self
    each_expression_with_index(&block)
  end
end

#extract_quantifier_target(quantifier_description) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/regexp_parser/expression/subexpression.rb', line 50

def extract_quantifier_target(quantifier_description)
  pre_quantifier_decorations = []
  target = expressions.reverse.find do |exp|
    if exp.decorative?
      exp.custom_to_s_handling = true
      pre_quantifier_decorations << exp.text
      next
    end
    exp
  end
  target or raise Regexp::Parser::ParserError,
    "No valid target found for '#{quantifier_description}' quantifier"

  target.pre_quantifier_decorations = pre_quantifier_decorations
  target
end

#flat_map(include_self = false, &block) ⇒ Object

Returns a new array with the results of calling the given block once for every expression. If a block is not given, returns an array with each expression and its level index as an array.



56
57
58
59
60
61
62
# File 'lib/regexp_parser/expression/methods/traverse.rb', line 56

def flat_map(include_self = false, &block)
  case block && block.arity
  when nil then each_expression(include_self).to_a
  when 2   then each_expression(include_self).map(&block)
  else          each_expression(include_self).map { |exp| block.call(exp) }
  end
end

#initialize_copy(orig) ⇒ Object

Override base method to clone the expressions as well.



13
14
15
16
17
18
# File 'lib/regexp_parser/expression/subexpression.rb', line 13

def initialize_copy(orig)
  self.expressions = orig.expressions.map do |exp|
    exp.clone.tap { |copy| copy.parent = self }
  end
  super
end

#inner_match_lengthObject



118
119
120
121
122
123
# File 'lib/regexp_parser/expression/methods/match_length.rb', line 118

def inner_match_length
  dummy = Regexp::Expression::Root.construct
  dummy.expressions = expressions.map(&:clone)
  dummy.quantifier = quantifier && quantifier.clone
  dummy.match_length
end

#match_lengthObject



111
112
113
114
115
116
# File 'lib/regexp_parser/expression/methods/match_length.rb', line 111

def match_length
  MatchLength.new(self,
                   base_min: map { |exp| exp.match_length.min }.inject(0, :+),
                   base_max: map { |exp| exp.match_length.max }.inject(0, :+),
                   reify: ->{ map { |exp| exp.match_length.to_re }.join })
end

#strfregexp_tree(format = '%a', include_self = true, separator = "\n") ⇒ Object Also known as: strfre_tree



102
103
104
105
106
107
108
109
110
# File 'lib/regexp_parser/expression/methods/strfregexp.rb', line 102

def strfregexp_tree(format = '%a', include_self = true, separator = "\n")
  output = include_self ? [self.strfregexp(format)] : []

  output += flat_map do |exp, index|
    exp.strfregexp(format, (include_self ? 1 : 0), index)
  end

  output.join(separator)
end

#teObject



39
40
41
# File 'lib/regexp_parser/expression/subexpression.rb', line 39

def te
  ts + base_length
end

#to_hObject



43
44
45
46
47
48
# File 'lib/regexp_parser/expression/subexpression.rb', line 43

def to_h
  attributes.merge(
    text:        to_s(:base),
    expressions: expressions.map(&:to_h)
  )
end

#traverse(include_self = false, &block) ⇒ Object Also known as: walk

Traverses the subexpression (depth-first, pre-order) and calls the given block for each expression with three arguments; the traversal event, the expression, and the index of the expression within its parent.

The event argument is passed as follows:

  • For subexpressions, :enter upon entering the subexpression, and :exit upon exiting it.

  • For terminal expressions, :visit is called once.

Returns self.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/regexp_parser/expression/methods/traverse.rb', line 32

def traverse(include_self = false, &block)
  return enum_for(__method__, include_self) unless block_given?

  block.call(:enter, self, 0) if include_self

  each_with_index do |exp, index|
    if exp.terminal?
      block.call(:visit, exp, index)
    else
      block.call(:enter, exp, index)
      exp.traverse(&block)
      block.call(:exit, exp, index)
    end
  end

  block.call(:exit, self, 0) if include_self

  self
end