Class: RepeatablePattern
- Inherits:
-
PatternBase
- Object
- PatternBase
- RepeatablePattern
- Defined in:
- lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb
Overview
RepeatablePattern provides quantifiers for patterns
Direct Known Subclasses
Instance Attribute Summary collapse
-
#at_least ⇒ Integer?
The minimum amount that can be matched.
-
#at_most ⇒ Integer?
The maximum amount that can be matched.
Attributes inherited from PatternBase
#arguments, #match, #next_pattern, #original_arguments
Instance Method Summary collapse
-
#add_quantifier_options_to(match, groups) ⇒ String
Adds quantifiers to match.
-
#do_add_attributes(indent) ⇒ String
return a string of any additional attributes that need to be added to the #to_s output indent is a string with the amount of space the parent block is indented, attributes are indented 2 more spaces called by #to_s.
-
#do_evaluate_self(groups) ⇒ String
evaluates @match.
-
#initialize(*arguments) ⇒ RepeatablePattern
constructor
Construct a new pattern.
-
#process_quantifiers_from_arguments ⇒ void
private
sets @at_least and @at_most based on arguments.
-
#quantifying_allowed? ⇒ Boolean
controls weather @arguments et.
-
#self_capture_group_rematch ⇒ Boolean
Does this pattern potentially rematch any capture groups.
-
#simple_quantifier ⇒ String
converts @at_least and @at_most into the appropriate quantifier this is a simple_quantifier because it does not include atomic-ness.
Methods inherited from PatternBase
#==, #__deep_clone__, #__deep_clone_self__, #collect_group_attributes, #convert_group_attributes_to_captures, #convert_includes_to_patterns, #do_collect_self_groups, #do_get_to_s_name, #each, #eql?, #evaluate, #evaluate_operator, #fixup_regex_references, #groupless, #groupless?, #hash, #insert, #insert!, #inspect, #lookAheadFor, #lookAheadToAvoid, #lookAround, #lookBehindFor, #lookBehindToAvoid, #map, #map!, #map_includes!, #matchResultOf, #maybe, #name, #needs_to_capture?, #oneOf, #oneOrMoreOf, #optimize_outer_group?, #or, #placeholder, #raise_if_regex_has_capture_group, #reTag, #recursivelyMatch, #resolve, #run_self_tests, #run_tests, #self_scramble_references, #single_entity?, #start_pattern, #then, #to_r, #to_s, #to_tag, #transform_includes, #transform_tag_as, #zeroOrMoreOf
Constructor Details
#initialize(pattern) ⇒ RepeatablePattern #initialize(opts) ⇒ RepeatablePattern #initialize(opts, deep_clone, original) ⇒ RepeatablePattern
Construct a new pattern
14 15 16 17 18 19 20 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 14 def initialize(*arguments) super(*arguments) @at_least = nil @at_most = nil process_quantifiers_from_arguments end |
Instance Attribute Details
#at_least ⇒ Integer?
Returns the minimum amount that can be matched.
10 11 12 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 10 def at_least @at_least end |
#at_most ⇒ Integer?
Returns the maximum amount that can be matched.
12 13 14 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 12 def at_most @at_most end |
Instance Method Details
#add_quantifier_options_to(match, groups) ⇒ String
Adds quantifiers to match
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 133 def (match, groups) match = match.evaluate(groups) if match.is_a? PatternBase quantifier = simple_quantifier # check if there are quantifiers if quantifier != "" # if the match is not a single entity, then it needs to be wrapped match = "(?:#{match})" unless string_single_entity?(match) # add the quantified ending match += quantifier elsif @arguments[:dont_back_track?] == true # make atomic, which allows arbitrary expression to be prevented from backtracking match = "(?>#{match})" end if @arguments[:word_cannot_be_any_of] word_pattern = @arguments[:word_cannot_be_any_of].map { |w| Regexp.escape w }.join "|" match = "(?!\\b(?:#{word_pattern})\\b)#{match}" end match end |
#do_add_attributes(indent) ⇒ String
return a string of any additional attributes that need to be added to the #to_s output indent is a string with the amount of space the parent block is indented, attributes are indented 2 more spaces called by #to_s
175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 175 def do_add_attributes(indent) # rubocop:disable Metrics/LineLength output = "" # special #then arguments if output += ",\n#{indent} at_least: " + @arguments[:at_least].to_s if @arguments[:at_least] output += ",\n#{indent} at_most: " + @arguments[:at_most].to_s if @arguments[:at_most] output += ",\n#{indent} how_many_times?: " + @arguments[:how_many_times?].to_s if @arguments[:how_many_times?] output += ",\n#{indent} word_cannot_be_any_of: " + @arguments[:word_cannot_be_any_of].to_s if @arguments[:word_cannot_be_any_of] end output += ",\n#{indent} dont_back_track?: " + @arguments[:dont_back_track?].to_s if @arguments[:dont_back_track?] output # rubocop:enable Metrics/LineLength end |
#do_evaluate_self(groups) ⇒ String
optionally override when inheriting
by default this optionally adds a capture group
evaluates @match
154 155 156 157 158 159 160 161 162 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 154 def do_evaluate_self(groups) match = (@match, groups) if self.needs_to_capture? match = "(#{match})" elsif not string_single_entity?(match) match = "(?:#{match})" end return match end |
#process_quantifiers_from_arguments ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
sets @at_least and @at_most based on arguments
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 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 29 def process_quantifiers_from_arguments # this sets the @at_most and @at_least value based on the arguments # # Simplify the quantity down to just :at_least and :at_most # attributes_clone = @arguments.clone # convert Enumerators to numbers [:at_least, :at_most, :how_many_times?].each do |each| if attributes_clone[each].is_a?(Enumerator) attributes_clone[each] = attributes_clone[each].size end end # canonize dont_back_track? and as_few_as_possible? @arguments[:dont_back_track?] ||= @arguments[:possessive?] @arguments[:as_few_as_possible?] ||= @arguments[:lazy?] # extract the data at_least = attributes_clone[:at_least] at_most = attributes_clone[:at_most] how_many_times = attributes_clone[:how_many_times?] # simplify to at_least and at_most at_least = at_most = how_many_times if how_many_times.is_a?(Integer) # check if quantifying is allowed # check after everything else in case additional quantifying options # are created in the future if @at_least = at_least @at_most = at_most # if a quantifying value was set and quantifying is not allowed, raise an error # telling the user that its not allowed elsif !(at_most.nil? && at_least.nil?) raise <<-HEREDOC.remove_indent Inside of the #{name} pattern, there are some quantity arguments like: :at_least :at_most or :how_many_times? These are not allowed in this kind of #{do_get_to_s_name}) pattern If you did this intentionally please wrap it inside of a Pattern.new() ex: #{do_get_to_s_name} Pattern.new( *your_arguments* ) ) HEREDOC end return unless @arguments[:dont_back_track?] && @arguments[:as_few_as_possible?] raise ":dont_back_track? and :as_few_as_possible? cannot both be provided" end |
#quantifying_allowed? ⇒ Boolean
override when inheriting. Return false unless the subclass allow quantifying
the default implementation returns True
controls weather @arguments et. al. set @at_most et. al.
168 169 170 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 168 def true end |
#self_capture_group_rematch ⇒ Boolean
this is used by FixRepeatedTagAs to modify patterns
Does this pattern potentially rematch any capture groups
The answer of true is a safe, but expensive to runtime, default
198 199 200 201 202 203 204 205 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 198 def self_capture_group_rematch # N or more return true if @at_most.nil? && !@at_least.nil? # up to N return true if !@at_most.nil? && @at_most > 1 false end |
#simple_quantifier ⇒ String
converts @at_least and @at_most into the appropriate quantifier this is a simple_quantifier because it does not include atomic-ness
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 |
# File 'lib/ruby_grammar_builder/pattern_variations/repeatable_pattern.rb', line 85 def simple_quantifier # Generate the ending based on :at_least and :at_most # by default assume no quantifiers quantifier = "" # if there is no at_least, at_most, or how_many_times?, then theres no quantifier if @at_least.nil? and @at_most.nil? quantifier = "" # if there is a quantifier else # if there's no at_least, then assume at_least = 1 @at_least = 1 if @at_least.nil? quantifier = if @at_least == 1 and @at_most == 1 # no qualifier "" elsif @at_least == 0 and @at_most == 1 # this is just a different way of "maybe" "?" elsif @at_least == 0 and @at_most.nil? # this is just a different way of "zeroOrMoreOf" "*" elsif @at_least == 1 and @at_most.nil? # this is just a different way of "oneOrMoreOf" "+" elsif @at_least == @at_most # exactly N times "{#{@at_least}}" else # if it is more complicated than that, just use a range "{#{@at_least},#{@at_most}}" end end # quantifiers can be made possessive without requiring atomic groups quantifier += "+" if quantifier != "" && @arguments[:dont_back_track?] == true quantifier += "?" if quantifier != "" && @arguments[:as_few_as_possible?] == true quantifier end |