Class: PatternBase
- Inherits:
-
Object
- Object
- PatternBase
- Defined in:
- lib/textmate_grammar/pattern_variations/base_pattern.rb,
lib/textmate_grammar/pattern_extensions/maybe.rb,
lib/textmate_grammar/pattern_extensions/one_of.rb,
lib/textmate_grammar/pattern_extensions/or_pattern.rb,
lib/textmate_grammar/pattern_extensions/placeholder.rb,
lib/textmate_grammar/pattern_extensions/look_ahead_for.rb,
lib/textmate_grammar/pattern_extensions/one_or_more_of.rb,
lib/textmate_grammar/pattern_extensions/look_behind_for.rb,
lib/textmate_grammar/pattern_extensions/match_result_of.rb,
lib/textmate_grammar/pattern_extensions/zero_or_more_of.rb,
lib/textmate_grammar/pattern_extensions/recursively_match.rb,
lib/textmate_grammar/pattern_extensions/lookaround_pattern.rb,
lib/textmate_grammar/pattern_extensions/look_ahead_to_avoid.rb,
lib/textmate_grammar/pattern_extensions/look_behind_to_avoid.rb
Overview
Users should not normally directly instantiate this class
Provides a base class to simplify the writing of complex regular expressions rules This class completely handles capture numbers and provides convenience methods for many common Regexp operations
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.
-
#add_capture_group_if_needed(regex_as_string) ⇒ String
Adds a capture group if needed.
-
#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
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 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 247 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/textmate_grammar/pattern_variations/base_pattern.rb', line 16 def arguments @arguments end |
#match ⇒ String, PatternBase
Returns The pattern to match.
14 15 16 |
# File 'lib/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/pattern_variations/base_pattern.rb', line 529 def ==(other) eql? other end |
#__deep_clone__ ⇒ PatternBase
Deeply clone self
833 834 835 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 833 def __deep_clone__ __deep_clone_self__.insert! @next_pattern.__deep_clone__ end |
#__deep_clone_self__ ⇒ PatternBase
Deeply clones self, without its next_pattern
842 843 844 845 846 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 842 def __deep_clone_self__ = @arguments.__deep_clone__ [:match] = @match.__deep_clone__ self.class.new(, :deep_clone, @original_arguments) end |
#add_capture_group_if_needed(regex_as_string) ⇒ String
Adds a capture group if needed
83 84 85 86 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 83 def add_capture_group_if_needed(regex_as_string) regex_as_string = "(#{regex_as_string})" if needs_to_capture? regex_as_string 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
663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 663 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
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 778 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
815 816 817 818 819 820 821 822 823 824 825 826 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 815 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
583 584 585 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 583 def do_add_attributes(indent) # rubocop:disable Lint/UnusedMethodArgument "" end |
#do_collect_self_groups(next_group) ⇒ Array<Hash>
Collect group information about self
685 686 687 688 689 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 685 def do_collect_self_groups(next_group) groups = [] groups << {group: next_group}.merge(@arguments) if 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 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 558 def do_evaluate_self(groups) match = @match match = match.evaluate(groups) if match.is_a? PatternBase add_capture_group_if_needed(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
596 597 598 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 596 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
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 133 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/textmate_grammar/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.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 334 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
569 570 571 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 569 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
710 711 712 713 714 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 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 710 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? raise "\nWhen processing the matchResultOf:#{match_reference}, I couldn't find the group it was referencing" end # if the reference does exist, then replace it with it's number "\\#{references[match_reference]}" 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? raise "\nWhen processing the recursivelyMatch:#{match_reference}, I couldn't find the group it was referencing" end # if the reference does exist, then replace it with it's number "\\g<#{references[match_reference]}>" end # rubocop:enable Metrics/LineLength self_regex end |
#groupless ⇒ PatternBase
create a copy of this pattern that contains no groups
612 613 614 615 616 617 618 619 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 612 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
606 607 608 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 606 def groupless? collect_group_attributes == [] end |
#hash ⇒ Integer
Gets the patterns Hashcode
507 508 509 510 511 512 |
# File 'lib/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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
696 697 698 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 696 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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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
121 122 123 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 121 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
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 96 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
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 157 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/textmate_grammar/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/textmate_grammar/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
295 296 297 298 299 300 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 295 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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/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/textmate_grammar/pattern_variations/base_pattern.rb', line 44 def optimize_outer_group? needs_to_capture? and @next_pattern.nil? end |
#or(pattern) ⇒ PatternBase
Match either the preceding pattern chain or pattern
50 51 52 |
# File 'lib/textmate_grammar/pattern_extensions/or_pattern.rb', line 50 def or(pattern) insert(OrPattern.new(pattern)) end |
#placeholder(placeholder) ⇒ PatternBase
Match a pattern that does not exist yet
83 84 85 |
# File 'lib/textmate_grammar/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
856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 856 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/textmate_grammar/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/textmate_grammar/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
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 633 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
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/textmate_grammar/pattern_variations/base_pattern.rb', line 438 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__ test_regex = copy.to_r test_fully_regex = wrap_with_anchors(copy).to_r 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
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 417 def run_tests 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 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
756 757 758 759 760 761 762 763 764 765 766 767 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 756 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
601 602 603 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 601 def single_entity? string_single_entity? 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/textmate_grammar/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/textmate_grammar/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
360 361 362 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 360 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
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 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 372 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
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 307 def to_tag output = { match: 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
181 182 183 184 185 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 181 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
194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/textmate_grammar/pattern_variations/base_pattern.rb', line 194 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/textmate_grammar/pattern_extensions/zero_or_more_of.rb', line 42 def zeroOrMoreOf(pattern) insert(ZeroOrMoreOfPattern.new(pattern)) end |