Class: PatternBase
- Inherits:
-
Object
- Object
- PatternBase
- Defined in:
- lib/ruby_grammar_builder/pattern_variations/base_pattern.rb,
lib/ruby_grammar_builder/pattern_extensions/maybe.rb,
lib/ruby_grammar_builder/pattern_extensions/one_of.rb,
lib/ruby_grammar_builder/pattern_extensions/or_pattern.rb,
lib/ruby_grammar_builder/pattern_extensions/placeholder.rb,
lib/ruby_grammar_builder/pattern_extensions/look_ahead_for.rb,
lib/ruby_grammar_builder/pattern_extensions/one_or_more_of.rb,
lib/ruby_grammar_builder/pattern_extensions/look_behind_for.rb,
lib/ruby_grammar_builder/pattern_extensions/match_result_of.rb,
lib/ruby_grammar_builder/pattern_extensions/zero_or_more_of.rb,
lib/ruby_grammar_builder/pattern_extensions/recursively_match.rb,
lib/ruby_grammar_builder/pattern_extensions/lookaround_pattern.rb,
lib/ruby_grammar_builder/pattern_extensions/look_ahead_to_avoid.rb,
lib/ruby_grammar_builder/pattern_extensions/look_behind_to_avoid.rb
Overview
Users should not normally directly instantiate this class
Direct Known Subclasses
LegacyPattern, LookAroundPattern, MatchResultOfPattern, OneOfPattern, OrPattern, PatternRange, PlaceholderPattern, RecursivelyMatchPattern, RepeatablePattern, TokenPattern
Instance Attribute Summary collapse
-
#arguments ⇒ Hash
The processed arguments.
-
#match ⇒ String, PatternBase
The pattern to match.
-
#next_pattern ⇒ PatternBase
The next pattern in the linked list of patterns.
-
#original_arguments ⇒ Hash
The original arguments passed into initialize.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Checks for equality A pattern is considered equal to another pattern if the result of tag_as is equivalent.
-
#__deep_clone__ ⇒ PatternBase
Deeply clone self.
-
#__deep_clone_self__ ⇒ PatternBase
Deeply clones self, without its next_pattern.
-
#collect_group_attributes(next_group = optimize_outer_group? ? 0 : 1) ⇒ Array<Hash>
private
Collects information about the capture groups.
-
#convert_group_attributes_to_captures(groups) ⇒ Hash
private
Converts group attributes into a captures hash.
-
#convert_includes_to_patterns(includes) ⇒ Array<Hash>
private
converts an includes array into a patterns array.
-
#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_collect_self_groups(next_group) ⇒ Array<Hash>
Collect group information about self.
-
#do_evaluate_self(groups) ⇒ String
evaluates @match.
-
#do_get_to_s_name(top_level) ⇒ String
What is the name of the method that the user would call top_level is if a freestanding or chaining function is called called by #to_s.
-
#each(each_includes = false) {|self| ... } ⇒ void
Call the block for each pattern in the list.
-
#eql?(other) ⇒ Boolean
Checks for equality A pattern is considered equal to another pattern if the result of tag_as is equivalent.
-
#evaluate(groups = nil, fixup_refereces: false) ⇒ String
evaluates the pattern into a string suitable for inserting into a grammar or constructing a Regexp.
-
#evaluate_operator ⇒ RegexOperator
Returns the operator to use when evaluating.
-
#fixup_regex_references(groups, self_regex) ⇒ String
private
Convert group references into backreferences.
-
#groupless ⇒ PatternBase
create a copy of this pattern that contains no groups.
-
#groupless? ⇒ Boolean
does this pattern contain no capturing groups.
-
#hash ⇒ Integer
Gets the patterns Hashcode.
-
#initialize(*arguments) ⇒ PatternBase
constructor
Construct a new pattern.
-
#insert(pattern) ⇒ PatternBase
Append pattern to a copy of the linked list of patterns.
-
#insert!(pattern) ⇒ self
Appends pattern to the linked list of patterns.
-
#inspect ⇒ String
Displays the Pattern for inspection.
-
#lookAheadFor(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookAheadFor.
-
#lookAheadToAvoid(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookAheadToAvoid.
-
#lookAround(pattern) ⇒ PatternBase
Looks around for the pattern.
-
#lookBehindFor(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookBehindFor.
-
#lookBehindToAvoid(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookBehindToAvoid.
-
#map(map_includes = false) {|self| ... } ⇒ self, PatternBase
Uses a block to transform all Patterns in the list.
-
#map!(map_includes = false) {|self| ... } ⇒ self
Uses a block to transform all Patterns in the list.
-
#map_includes! {|self| ... } ⇒ void
private
Uses a block to transform all Patterns in all includes.
-
#matchResultOf(reference) ⇒ PatternBase
Match the result of some other pattern.
-
#maybe(pattern) ⇒ PatternBase
Optionally match pattern.
-
#name ⇒ String
attempts to provide a memorable name for a pattern.
-
#needs_to_capture? ⇒ Boolean
does @arguments contain any attributes that require this pattern be captured?.
-
#oneOf(patterns) ⇒ PatternBase
Match one of the supplied patterns.
-
#oneOrMoreOf(pattern) ⇒ PatternBase
Match pattern one or more times.
-
#optimize_outer_group? ⇒ Boolean
Can the capture be optimized out.
-
#or(pattern) ⇒ PatternBase
Match either the preceding pattern chain or pattern.
-
#placeholder(placeholder) ⇒ PatternBase
Match a pattern that does not exist yet.
-
#raise_if_regex_has_capture_group(regex, check = 1) ⇒ void
Raise an error if regex contains a capturing group.
-
#recursivelyMatch(reference) ⇒ PatternBase
Recursively match some outer pattern.
-
#resolve(repository) ⇒ PatternBase
Resolves any placeholder patterns.
-
#reTag(args) ⇒ PatternBase
Retags all tags_as.
-
#run_self_tests ⇒ Boolean
Runs the unit tests for self.
-
#run_tests ⇒ Boolean
Runs the unit tests, recursively.
-
#self_scramble_references ⇒ void
Scrambles references of self This method provides a way to rename all references both actual references and references to references will be scrambled in some one to one mapping, all references that were unique before remain unique.
- #single_entity? ⇒ Boolean
-
#start_pattern ⇒ self
To aid in Linters all Patterns support start_pattern which return the pattern for initial match, for a single match pattern that is itself.
-
#then(pattern) ⇒ PatternBase
Construct a new pattern and append to the end.
-
#to_r(groups = nil) ⇒ Regexp
converts a pattern to a Regexp.
-
#to_s(depth = 0, top_level = true) ⇒ String
Displays the PatternBase as you would write it in code.
-
#to_tag ⇒ Hash
converts a PatternBase to a Hash representing a textmate rule.
-
#transform_includes {|PatternBase, Symbol, Regexp, String| ... } ⇒ PatternBase
Uses block to recursively transform includes.
-
#transform_tag_as {|String| ... } ⇒ PatternBase
Uses block to recursively transform tag_as.
-
#zeroOrMoreOf(pattern) ⇒ PatternBase
Match pattern zero or more times.
Constructor Details
#initialize(pattern) ⇒ PatternBase #initialize(opts) ⇒ PatternBase #initialize(opts, deep_clone, original) ⇒ PatternBase
Construct a new pattern
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 235 def initialize(*arguments) if arguments.length > 1 && arguments[1] == :deep_clone @arguments = arguments[0] @match = @arguments[:match] @arguments.delete(:match) @original_arguments = arguments[2] @next_pattern = nil return end if arguments.length > 1 # PatternBase was likely constructed like `PatternBase.new(/foo/, option: bar)` puts "PatternBase#new() expects a single Regexp, String, or Hash" puts "PatternBase#new() was provided with multiple arguments" puts "arguments:" puts arguments raise "See error above" end @next_pattern = nil arg1 = arguments[0] arg1 = {match: arg1} unless arg1.is_a? Hash @original_arguments = arg1.clone if arg1[:match].is_a? String arg1[:match] = Regexp.escape(arg1[:match]).gsub("/", "\\/") @match = arg1[:match] elsif arg1[:match].is_a? Regexp raise_if_regex_has_capture_group arg1[:match] @match = arg1[:match].inspect[1..-2] # convert to string and remove the slashes elsif arg1[:match].is_a? PatternBase @match = arg1[:match] else puts <<-HEREDOC.remove_indent Pattern.new() must be constructed with a String, Regexp, or Pattern Provided arguments: #{@original_arguments} HEREDOC raise "See error above" end # ensure that includes is either nil or a flat array if arg1[:includes] arg1[:includes] = [arg1[:includes]] unless arg1[:includes].is_a? Array arg1[:includes] = arg1[:includes].flatten end arg1.delete(:match) @arguments = arg1 end |
Instance Attribute Details
#arguments ⇒ Hash
Returns The processed arguments.
16 17 18 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 16 def arguments @arguments end |
#match ⇒ String, PatternBase
Returns The pattern to match.
14 15 16 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 14 def match @match end |
#next_pattern ⇒ PatternBase
Returns The next pattern in the linked list of patterns.
12 13 14 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 12 def next_pattern @next_pattern end |
#original_arguments ⇒ Hash
Returns The original arguments passed into initialize.
18 19 20 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 18 def original_arguments @original_arguments end |
Instance Method Details
#==(other) ⇒ Boolean
Checks for equality A pattern is considered equal to another pattern if the result of tag_as is equivalent
529 530 531 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 529 def ==(other) eql? other end |
#__deep_clone__ ⇒ PatternBase
Deeply clone self
847 848 849 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 847 def __deep_clone__ __deep_clone_self__.insert! @next_pattern.__deep_clone__ end |
#__deep_clone_self__ ⇒ PatternBase
Deeply clones self, without its next_pattern
856 857 858 859 860 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 856 def __deep_clone_self__ = @arguments.__deep_clone__ [:match] = @match.__deep_clone__ self.class.new(, :deep_clone, @original_arguments) end |
#collect_group_attributes(next_group = optimize_outer_group? ? 0 : 1) ⇒ Array<Hash>
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.
Collects information about the capture groups
668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 668 def collect_group_attributes(next_group = optimize_outer_group? ? 0 : 1) groups = do_collect_self_groups(next_group) next_group += groups.length if @match.is_a? PatternBase new_groups = @match.collect_group_attributes(next_group) groups.concat(new_groups) next_group += new_groups.length end if @next_pattern.is_a? PatternBase new_groups = @next_pattern.collect_group_attributes(next_group) groups.concat(new_groups) end groups end |
#convert_group_attributes_to_captures(groups) ⇒ Hash
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.
Converts group attributes into a captures hash
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 792 def convert_group_attributes_to_captures(groups) captures = {} groups.each do |group| output = {} output[:name] = group[:tag_as] unless group[:tag_as].nil? if group[:includes].is_a? Array output[:patterns] = convert_includes_to_patterns(group[:includes]) elsif !group[:includes].nil? output[:patterns] = convert_includes_to_patterns([group[:includes]]) end captures[group[:group].to_s] = output end # replace $match and $reference() with the appropriate capture number captures.each do |key, value| next if value[:name].nil? value[:name] = value[:name].gsub(/\$(?:match|reference\((.+)\))/) do |match| next ("$" + key) if match == "$match" reference_group = groups.detect do |group| group[:reference] == Regexp.last_match(1) end "$" + reference_group[:group].to_s end end end |
#convert_includes_to_patterns(includes) ⇒ Array<Hash>
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.
converts an includes array into a patterns array
829 830 831 832 833 834 835 836 837 838 839 840 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 829 def convert_includes_to_patterns(includes) includes = [includes] unless includes.is_a? Array patterns = includes.flatten.map do |rule| next {include: rule} if rule.is_a?(String) && rule.start_with?("source.", "text.") next {include: rule.to_s} if [:$self, :$base].include? rule next {include: "##{rule}"} if rule.is_a? Symbol rule = PatternBase.new(rule) unless rule.is_a? PatternBase rule.to_tag end patterns 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
588 589 590 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 588 def do_add_attributes(indent) # rubocop:disable Lint/UnusedMethodArgument "" end |
#do_collect_self_groups(next_group) ⇒ Array<Hash>
Collect group information about self
690 691 692 693 694 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 690 def do_collect_self_groups(next_group) groups = [] groups << {group: next_group}.merge(@arguments) if self.needs_to_capture? groups end |
#do_evaluate_self(groups) ⇒ String
optionally override when inheriting
by default this optionally adds a capture group
evaluates @match
558 559 560 561 562 563 564 565 566 567 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 558 def do_evaluate_self(groups) match = @match match = match.evaluate(groups) if match.is_a? PatternBase if self.needs_to_capture? match = "(#{match})" elsif not string_single_entity?(match) match = "(?:#{match})" end return match end |
#do_get_to_s_name(top_level) ⇒ String
What is the name of the method that the user would call top_level is if a freestanding or chaining function is called called by #to_s
601 602 603 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 601 def do_get_to_s_name(top_level) top_level ? "Pattern.new(" : ".then(" end |
#each(each_includes = false) {|self| ... } ⇒ void
This method returns an undefined value.
Call the block for each pattern in the list
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 121 def each(each_includes = false, &block) yield self @match.each(each_includes, &block) if @match.is_a? PatternBase @next_pattern.each(each_includes, &block) if @next_pattern.is_a? PatternBase return unless each_includes return unless @arguments[:includes].is_a? Array @arguments[:includes].each do |s| next unless s.is_a? Pattern s.each(true, &block) end end |
#eql?(other) ⇒ Boolean
Checks for equality A pattern is considered equal to another pattern if the result of tag_as is equivalent
522 523 524 525 526 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 522 def eql?(other) return false unless other.is_a? PatternBase to_tag == other.to_tag end |
#evaluate(groups = nil, fixup_refereces: false) ⇒ String
evaluates the pattern into a string suitable for inserting into a grammar or constructing a Regexp.
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 322 def evaluate(groups = nil, fixup_refereces: false) top_level = groups.nil? groups = collect_group_attributes if top_level evaluate_array = [''] pat = self while pat.is_a? PatternBase evaluate_array << pat.evaluate_operator evaluate_array << pat.do_evaluate_self(groups) pat = pat.next_pattern end self_evaluate = RegexOperator.evaluate(evaluate_array) self_evaluate = fixup_regex_references(groups, self_evaluate) if top_level || fixup_refereces self_evaluate end |
#evaluate_operator ⇒ RegexOperator
Returns the operator to use when evaluating
574 575 576 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 574 def evaluate_operator ConcatOperator.new end |
#fixup_regex_references(groups, self_regex) ⇒ String
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.
Convert group references into backreferences
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 715 def fixup_regex_references(groups, self_regex) # rubocop:disable Metrics/LineLength references = {} # convert all references to group numbers groups.each do |group| references[group[:reference]] = group[:group] unless group[:reference].nil? end # convert back references self_regex = self_regex.gsub(/\(\?\#\[:backreference:([^\\]+?):\]\)/) do match_reference = Regexp.last_match(1) if references[match_reference].nil? if $ruby_grammar_builder__unit_test_active "(?#would_be_backref_but_null_because_unit_test)A(?<=B)" else raise "groups:#{groups}\nreferences: #{references}\nWhen processing the matchResultOf:#{match_reference}, I couldn't find the group it was referencing" end else # if the reference does exist, then replace it with it's number "(?:\\#{references[match_reference]})" end end # check for a subroutine to the Nth group, replace it with `\N` self_regex = self_regex.gsub(/\(\?\#\[:subroutine:([^\\]+?):\]\)/) do match_reference = Regexp.last_match(1) if references[match_reference].nil? if $ruby_grammar_builder__unit_test_active "(?#would_be_subroutine_but_null_because_unit_test)A(?<=B)" else raise "groups:#{groups}\nreferences: #{references}\nWhen processing the recursivelyMatch:#{match_reference}, I couldn't find the group it was referencing" end else # if the reference does exist, then replace it with it's number "\\g<#{references[match_reference]}>" end end # rubocop:enable Metrics/LineLength self_regex end |
#groupless ⇒ PatternBase
create a copy of this pattern that contains no groups
617 618 619 620 621 622 623 624 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 617 def groupless __deep_clone__.map! do |s| s.arguments.delete(:tag_as) s.arguments.delete(:reference) s.arguments.delete(:includes) raise "unable to remove capture" if s.needs_to_capture? end.freeze end |
#groupless? ⇒ Boolean
does this pattern contain no capturing groups
611 612 613 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 611 def groupless? collect_group_attributes == [] end |
#hash ⇒ Integer
Gets the patterns Hashcode
507 508 509 510 511 512 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 507 def hash # TODO: find a better hash code # PatternBase.new("abc") == PatternBase.new(PatternBase.new("abc")) # but PatternBase.new("abc").hash != PatternBase.new(PatternBase.new("abc")).hash @match.hash end |
#insert(pattern) ⇒ PatternBase
Append pattern to a copy of the linked list of patterns
71 72 73 74 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 71 def insert(pattern) new_pattern = __deep_clone__ new_pattern.insert!(pattern).freeze end |
#insert!(pattern) ⇒ self
Appends pattern to the linked list of patterns
57 58 59 60 61 62 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 57 def insert!(pattern) last = self last = last.next_pattern while last.next_pattern last.next_pattern = pattern self end |
#inspect ⇒ String
Displays the Pattern for inspection
701 702 703 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 701 def inspect super.split(" ")[0] + " match:" + @match.inspect + ">" end |
#lookAheadFor(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookAheadFor
14 15 16 17 18 19 20 21 |
# File 'lib/ruby_grammar_builder/pattern_extensions/look_ahead_for.rb', line 14 def lookAheadFor(pattern) if pattern.is_a? Hash pattern[:type] = :lookAheadFor else pattern = {match: pattern, type: :lookAheadFor} end lookAround(pattern) end |
#lookAheadToAvoid(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookAheadToAvoid
98 99 100 101 102 103 104 105 |
# File 'lib/ruby_grammar_builder/pattern_extensions/lookaround_pattern.rb', line 98 def lookAheadToAvoid(pattern) if pattern.is_a? Hash pattern[:type] = :lookAheadToAvoid else pattern = {match: pattern, type: :lookAheadToAvoid} end lookAround(pattern) end |
#lookAround(pattern) ⇒ PatternBase
Looks around for the pattern
option [Symbol] :type the look-around type
can be one of :lookAheadFor, :lookAheadToAvoid, :lookBehindFor, :lookBehindToAvoid
55 56 57 |
# File 'lib/ruby_grammar_builder/pattern_extensions/lookaround_pattern.rb', line 55 def lookAround(pattern) insert(LookAroundPattern.new(pattern)) end |
#lookBehindFor(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookBehindFor
13 14 15 16 17 18 19 20 |
# File 'lib/ruby_grammar_builder/pattern_extensions/look_behind_for.rb', line 13 def lookBehindFor(pattern) if pattern.is_a? Hash pattern[:type] = :lookBehindFor else pattern = {match: pattern, type: :lookBehindFor} end lookAround(pattern) end |
#lookBehindToAvoid(pattern) ⇒ PatternBase
Equivalent to lookAround with type set to :lookBehindToAvoid
66 67 68 69 70 71 72 73 |
# File 'lib/ruby_grammar_builder/pattern_extensions/lookaround_pattern.rb', line 66 def lookBehindToAvoid(pattern) if pattern.is_a? Hash pattern[:type] = :lookBehindToAvoid else pattern = {match: pattern, type: :lookBehindToAvoid} end lookAround(pattern) end |
#map(map_includes = false) {|self| ... } ⇒ self, PatternBase
Uses a block to transform all Patterns in the list
109 110 111 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 109 def map(map_includes = false, &block) __deep_clone__.map!(map_includes, &block).freeze end |
#map!(map_includes = false) {|self| ... } ⇒ self
Uses a block to transform all Patterns in the list
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 84 def map!(map_includes = false, &block) yield self if @match.is_a? PatternBase if @match.frozen? puts "frozen @match" puts @match.inspect end @match = @match.map!(map_includes, &block) end if @next_pattern.is_a? PatternBase if @next_pattern.frozen? puts "frozen @next_pattern" puts @next_pattern.inspect end @next_pattern = @next_pattern.map!(map_includes, &block) end map_includes!(&block) if map_includes self end |
#map_includes! {|self| ... } ⇒ 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.
only for use by map!
This method returns an undefined value.
Uses a block to transform all Patterns in all includes
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 145 def map_includes!(&block) return unless @arguments[:includes].is_a? Array @arguments[:includes].map! do |s| if s.is_a? PatternBase if s.frozen? puts "frozen s" puts s.inspect end end next s.map!(true, &block) if s.is_a? PatternBase next s end end |
#matchResultOf(reference) ⇒ PatternBase
Match the result of some other pattern
59 60 61 |
# File 'lib/ruby_grammar_builder/pattern_extensions/match_result_of.rb', line 59 def matchResultOf(reference) insert(MatchResultOfPattern.new(reference)) end |
#maybe(pattern) ⇒ PatternBase
Optionally match pattern
42 43 44 |
# File 'lib/ruby_grammar_builder/pattern_extensions/maybe.rb', line 42 def maybe(pattern) insert(MaybePattern.new(pattern)) end |
#name ⇒ String
attempts to provide a memorable name for a pattern
283 284 285 286 287 288 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 283 def name return @arguments[:reference] unless @arguments[:reference].nil? return @arguments[:tag_as] unless @arguments[:tag_as].nil? to_s end |
#needs_to_capture? ⇒ Boolean
does @arguments contain any attributes that require this pattern be captured?
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 25 def needs_to_capture? capturing_attributes = [ :tag_as, :reference, :includes, ] puts @match.class unless @arguments.is_a? Hash !(@arguments.keys & capturing_attributes).empty? end |
#oneOf(patterns) ⇒ PatternBase
Match one of the supplied patterns
97 98 99 |
# File 'lib/ruby_grammar_builder/pattern_extensions/one_of.rb', line 97 def oneOf(patterns) insert(OneOfPattern.new(patterns)) end |
#oneOrMoreOf(pattern) ⇒ PatternBase
Match pattern one or more times
34 35 36 |
# File 'lib/ruby_grammar_builder/pattern_extensions/one_or_more_of.rb', line 34 def oneOrMoreOf(pattern) insert(OneOrMoreOfPattern.new(pattern)) end |
#optimize_outer_group? ⇒ Boolean
Can the capture be optimized out
When the pattern has nothing after it then its capture can instead become capture group 0
44 45 46 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 44 def optimize_outer_group? self.needs_to_capture? and @next_pattern.nil? end |
#or(pattern) ⇒ PatternBase
Match either the preceding pattern chain or pattern
104 105 106 |
# File 'lib/ruby_grammar_builder/pattern_extensions/or_pattern.rb', line 104 def or(pattern) insert(OrPattern.new(pattern)) end |
#placeholder(placeholder) ⇒ PatternBase
Match a pattern that does not exist yet
83 84 85 |
# File 'lib/ruby_grammar_builder/pattern_extensions/placeholder.rb', line 83 def placeholder(placeholder) insert(PlaceholderPattern.new(placeholder)) end |
#raise_if_regex_has_capture_group(regex, check = 1) ⇒ void
This method returns an undefined value.
Raise an error if regex contains a capturing group
870 871 872 873 874 875 876 877 878 879 880 881 882 883 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 870 def raise_if_regex_has_capture_group(regex, check = 1) # this will throw a RegexpError if there are no capturing groups _ignore = with_no_warnings { /#{regex}#{"\\" + check.to_s}/ } # at this point @match contains a capture group, complain raise <<-HEREDOC.remove_indent There is a pattern that is being constructed from a regular expression with a capturing group. This is not allowed, as the group cannot be tracked The bad pattern is #{self} HEREDOC rescue RegexpError # rubocop: disable Lint/HandleExceptions # no capture groups present, purposely do nothing end |
#recursivelyMatch(reference) ⇒ PatternBase
Recursively match some outer pattern
68 69 70 |
# File 'lib/ruby_grammar_builder/pattern_extensions/recursively_match.rb', line 68 def recursivelyMatch(reference) insert(RecursivelyMatchPattern.new(reference)) end |
#resolve(repository) ⇒ PatternBase
Resolves any placeholder patterns
94 95 96 |
# File 'lib/ruby_grammar_builder/pattern_extensions/placeholder.rb', line 94 def resolve(repository) __deep_clone__.map!(true) { |s| s.resolve!(repository) if s.respond_to? :resolve! }.freeze end |
#reTag(args) ⇒ PatternBase
Retags all tags_as
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 638 def reTag(args) __deep_clone__.map! do |s| # tags are keep unless `all: false` or `keep: false`, and append is not a string discard_tag = (args[:all] == false || args[:keep] == false) discard_tag = false if args[:append].is_a? String args.each do |key, tag| if [s.arguments[:tag_as], s.arguments[:reference]].include? key s.arguments[:tag_as] = tag discard_tag = false end end if args[:append].is_a?(String) && s.arguments[:tag_as] s.arguments[:tag_as] = s.arguments[:tag_as] + "." + args[:append] end s.arguments.delete(:tag_as) if discard_tag end.freeze end |
#run_self_tests ⇒ Boolean
Runs the unit tests for self
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 429 def run_self_tests pass = [true] # some patterns are not able to be evaluated # do not attempt to unless required return true unless [ :should_fully_match, :should_not_fully_match, :should_partially_match, :should_not_partially_match, ].any? { |k| @arguments.include? k } copy = __deep_clone_self__ begin test_regex = copy.to_r test_fully_regex = wrap_with_anchors(copy).to_r rescue => exception raise <<~HEREDOC error running unit tests for: #{copy} #{exception} HEREDOC end warn = lambda do |symbol| puts [ "", "When testing the pattern #{test_regex.inspect}. The unit test for #{symbol} failed.", "The unit test has the following patterns:", "#{@arguments[symbol].to_yaml}", "The Failing pattern is below:", "#{self}", ].join("\n") end if @arguments[:should_fully_match].is_a? Array unless @arguments[:should_fully_match].all? { |test| test =~ test_fully_regex } warn.call :should_fully_match pass << false end end if @arguments[:should_not_fully_match].is_a? Array unless @arguments[:should_not_fully_match].none? { |test| test =~ test_fully_regex } warn.call :should_not_fully_match pass << false end end if @arguments[:should_partially_match].is_a? Array unless @arguments[:should_partially_match].all? { |test| test =~ test_regex } warn.call :should_partially_match pass << false end end if @arguments[:should_not_partially_match].is_a? Array unless @arguments[:should_not_partially_match].none? { |test| test =~ test_regex } warn.call :should_not_partially_match pass << false end end pass.none?(&:!) end |
#run_tests ⇒ Boolean
Runs the unit tests, recursively
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 405 def run_tests original_flag_value = $ruby_grammar_builder__unit_test_active $ruby_grammar_builder__unit_test_active = true pass = [ run_self_tests, ] # run related unit tests pass << @match.run_tests if @match.is_a? PatternBase pass << @next_pattern.run_tests if @next_pattern.is_a? PatternBase if @arguments[:includes].is_a? Array @arguments[:includes]&.each { |inc| pass << inc.run_tests if inc.is_a? PatternBase } elsif @arguments[:includes].is_a? PatternBase pass << @arguments[:includes].run_tests end $ruby_grammar_builder__unit_test_active = original_flag_value pass.none?(&:!) end |
#self_scramble_references ⇒ void
This method returns an undefined value.
Scrambles references of self This method provides a way to rename all references both actual references and references to references will be scrambled in some one to one mapping, all references that were unique before remain unique
This must be idempotent, calling this repeatedly must have references be as if it was called only once, even if the pattern is cloned between calls
this is because it may be called a different number of times depending on the nest
level of the patterns
770 771 772 773 774 775 776 777 778 779 780 781 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 770 def self_scramble_references scramble = lambda do |name| return name if name.start_with?("__scrambled__") "__scrambled__" + name end tag_as = @arguments[:tag_as] reference = @arguments[:reference] @arguments[:tag_as] = scramble.call(tag_as) if tag_as.is_a? String @arguments[:reference] = scramble.call(reference) if reference.is_a? String end |
#single_entity? ⇒ Boolean
606 607 608 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 606 def single_entity? return string_single_entity?( self.evaluate() ) end |
#start_pattern ⇒ self
To aid in Linters all Patterns support start_pattern which return the pattern for initial match, for a single match pattern that is itself
498 499 500 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 498 def start_pattern self end |
#then(pattern) ⇒ PatternBase
Construct a new pattern and append to the end
541 542 543 544 545 546 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 541 def then(pattern) unless pattern.is_a?(PatternBase) && pattern.next_pattern.nil? pattern = Pattern.new(pattern) end insert(pattern) end |
#to_r(groups = nil) ⇒ Regexp
converts a pattern to a Regexp
348 349 350 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 348 def to_r(groups = nil) with_no_warnings { Regexp.new(evaluate(groups)) } end |
#to_s(depth = 0, top_level = true) ⇒ String
Displays the PatternBase as you would write it in code
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 360 def to_s(depth = 0, top_level = true) # TODO: make this method easier to understand # rubocop:disable Metrics/LineLength begin plugins = Grammar.plugins plugins.reject! { |p| (@original_arguments.keys & p.class.).empty? } regex_as_string = case @original_arguments[:match] when PatternBase then @original_arguments[:match].to_s(depth + 2, true) when Regexp then @original_arguments[:match].inspect when String then "/" + Regexp.escape(@original_arguments[:match]) + "/" end indent = " " * depth output = indent + do_get_to_s_name(top_level) # basic pattern information output += "\n#{indent} match: " + regex_as_string.lstrip output += ",\n#{indent} tag_as: \"" + @arguments[:tag_as] + '"' if @arguments[:tag_as] output += ",\n#{indent} reference: \"" + @arguments[:reference] + '"' if @arguments[:reference] # unit tests output += ",\n#{indent} should_fully_match: " + @arguments[:should_fully_match].to_s if @arguments[:should_fully_match] output += ",\n#{indent} should_not_fully_match: " + @arguments[:should_not_fully_match].to_s if @arguments[:should_not_fully_match] output += ",\n#{indent} should_partially_match: " + @arguments[:should_partially_match].to_s if @arguments[:should_partially_match] output += ",\n#{indent} should_not_partially_match: " + @arguments[:should_not_partially_match].to_s if @arguments[:should_not_partially_match] output += ",\n#{indent} includes: " + @arguments[:includes].to_s if @arguments[:includes] # add any linter/transform configurations plugins.each { |p| output += p.(indent + " ", @original_arguments) } # subclass, ending and recursive output += do_add_attributes(indent) output += ",\n#{indent})" output += @next_pattern.to_s(depth, false).lstrip if @next_pattern output rescue return @original_arguments.to_s end # rubocop:enable Metrics/LineLength end |
#to_tag ⇒ Hash
converts a PatternBase to a Hash representing a textmate rule
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 295 def to_tag output = { match: self.evaluate(), } output[:captures] = convert_group_attributes_to_captures(collect_group_attributes) if optimize_outer_group? # optimize captures by removing outermost output[:match] = output[:match][1..-2] output[:name] = output[:captures]["0"][:name] output[:captures]["0"].delete(:name) output[:captures].reject! { |_, v| !v || v.empty? } end output.reject! { |_, v| !v || v.empty? } output end |
#transform_includes {|PatternBase, Symbol, Regexp, String| ... } ⇒ PatternBase
Uses block to recursively transform includes
169 170 171 172 173 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 169 def transform_includes(&block) map(true) do |s| s.arguments[:includes].map!(&block) if s.arguments[:includes].is_a? Array end end |
#transform_tag_as {|String| ... } ⇒ PatternBase
Uses block to recursively transform tag_as
182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/ruby_grammar_builder/pattern_variations/base_pattern.rb', line 182 def transform_tag_as(&block) __deep_clone__.map! do |s| s.arguments[:tag_as] = block.call(s.arguments[:tag_as]) if s.arguments[:tag_as] next unless s.arguments[:includes].is_a?(Array) s.arguments[:includes].map! do |i| next i unless i.is_a? PatternBase i.transform_tag_as(&block) end end.freeze end |
#zeroOrMoreOf(pattern) ⇒ PatternBase
Match pattern zero or more times
42 43 44 |
# File 'lib/ruby_grammar_builder/pattern_extensions/zero_or_more_of.rb', line 42 def zeroOrMoreOf(pattern) insert(ZeroOrMoreOfPattern.new(pattern)) end |