Module: Contrast::Agent::Assess::Property::Tagged

Includes:
Utils::Assess::TaggedUtils
Included in:
Contrast::Agent::Assess::Properties
Defined in:
lib/contrast/agent/assess/property/tagged.rb

Overview

This module serves to hold the functionality required for the management of our dataflow tags.

Instance Method Summary collapse

Methods included from Utils::Assess::TaggedUtils

#add_tag, #any_tags_between?, #cleanup_tags, #clear_tags, #delete_tags, #fetch_tag, #get_tags, #set_tags, #tag_keys, #tagged?, #tags_at, #tags_at_range

Instance Method Details

#delete_tags_at_ranges(ranges, shift: true) ⇒ Object

Remove all tags within the given ranges. This does not delete an entire tag if part of that tag is outside this range, meaning we may reduce sizes of tags or split them.

If shift is true, it is assumed the characters at those ranges were removed. If shift is false, it is assumed those ranges were replaced by the same number of characters and no shift is needed.

current tags: 0-15 range: 5-10 result: 0-5, 10-15

Parameters:

  • ranges (Array<Range>)

    the ranges to delete

  • shift (Boolean) (defaults to: true)

    move remaining tags to the left to account for the deletion



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/contrast/agent/assess/property/tagged.rb', line 43

def delete_tags_at_ranges ranges, shift: true
  return unless tracked?

  # Stage one - delete the tags w/o changing their
  # location.
  ranges.each do |range|
    remove_tags(range)
  end
  return unless shift

  # the amount we've already removed from the string
  shift = 0
  # Stage two - shift the tags to the left to account
  # for the sections that were deleted.
  ranges.each do |range|
    shift_tags_for_deletion(range, shift)
    shift += (range.end - range.begin)
  end

  # Clean up and merge any touching tags
  Contrast::Utils::TagUtil.merge_tags(tags)
end

#remove_tags(range) ⇒ Object

Remove the tag ranges covering the given range and appends any trailing value that might exist after removal of range



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/contrast/agent/assess/property/tagged.rb', line 84

def remove_tags range
  return unless tracked?

  full_delete = []
  tags.each_pair do |key, value|
    remove = []
    add = []
    value.each do |tag|
      comparison = tag.compare_range(range.begin, range.end)
      # ABOVE and BELOW are not affected by this check
      tags_remove_comparison(comparison, tag, remove, add, range)
    end
    value.delete_if { |tag| remove.include?(tag) }
    Contrast::Utils::TagUtil.ordered_merge(value, add)
    full_delete << key if value.empty?
  end
  full_delete.each { |key| tags.delete(key) }
end

#shift_tags(ranges) ⇒ Object

Shift all the tags in this object by the given ranges. This method assumes the ranges are sorted, meaning the leftmost (lowest) range is first

current tags: 0-15 range: 5-10 result: 0-5, 10-20



73
74
75
76
77
78
79
# File 'lib/contrast/agent/assess/property/tagged.rb', line 73

def shift_tags ranges
  return unless tracked?

  ranges.each do |range|
    shift_tags_for_insertion(range)
  end
end

#shift_tags_comparison(comparison, add, tag, length, range) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/contrast/agent/assess/property/tagged.rb', line 175

def shift_tags_comparison comparison, add, tag, length, range
  case comparison
    # part of the tag is being inserted on
  when Contrast::Agent::Assess::Tag::LOW_SPAN
    new_tag = tag.clone
    new_tag.update_start(range.begin)
    new_tag.shift(length)
    add << new_tag
    tag.update_end(range.begin)
    # the tag exists in the inserted range. it is partially shifted
  when Contrast::Agent::Assess::Tag::WITHIN
    tag.shift(length)
    # the tag spans the range. leave the part below alone
  when Contrast::Agent::Assess::Tag::WITHOUT # rubocop:disable Lint/DuplicateBranch
    new_tag = tag.clone
    new_tag.update_start(range.begin)
    new_tag.shift(length)
    add << new_tag
    tag.update_end(range.begin)
  when Contrast::Agent::Assess::Tag::HIGH_SPAN, Contrast::Agent::Assess::Tag::ABOVE # rubocop:disable Lint/DuplicateBranch
    tag.shift(length)
  end
end

#shift_tags_for_deletion(range, shift) ⇒ Object

Shift the tag ranges covering the given range We assume this is for a deletion, meaning we have to move tags to the left

Parameters:

  • range (Range)

    the range to delete

  • shift (Boolean)

    move remaining tags to the left to account for the deletion



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/contrast/agent/assess/property/tagged.rb', line 132

def shift_tags_for_deletion range, shift
  return unless tracked?

  tags.each_value do |value|
    value.each do |tag|
      comparison = tag.compare_range(range.begin - shift, range.end - shift)
      # this is really the only thing we need to shift
      next unless comparison == Contrast::Agent::Assess::Tag::ABOVE

      length = range.end - range.begin
      tag.shift(0 - length)
    end
  end
end

#shift_tags_for_insertion(range) ⇒ Object

Shift the tag ranges covering the given range to account for new data being added. We assume this is for a insertion, meaning we have to move tags out of the range and to the right. For example, given current tags: 0-15 when we insert a range: 5-10 then the result is: 0-5, 10-20

Note that we disable Lint/DuplicateBranch in this branch in order list out all tag range cases in the proper order to make this easier to understand

Parameters:

  • range (Range)

    the range of new information that’s been inserted



160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/contrast/agent/assess/property/tagged.rb', line 160

def shift_tags_for_insertion range
  return unless tracked?

  tags.each_value do |value|
    add = []
    value.each do |tag|
      comparison = tag.compare_range(range.begin, range.end)
      length = range.end - range.begin
      # BELOW is not affected by this check
      shift_tags_comparison(comparison, add, tag, length, range)
    end
    Contrast::Utils::TagUtil.ordered_merge(value, add)
  end
end

#tags_remove_comparison(comparison, tag, remove, add, range) ⇒ Object

This method is for the tags comparison the idea is to move the whole case here

Parameters:

  • comparison (String)

    indicates type of removal is to occur

  • tag

    Contrast::Agent::Assess::Tag

  • remove (String)

    holds removed Tag if exists

  • add (String)

    holds trailing Tag if exists

  • range (Range)

    start and stop for idx for removal



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/contrast/agent/assess/property/tagged.rb', line 110

def tags_remove_comparison comparison, tag, remove, add, range
  case comparison
  when Contrast::Agent::Assess::Tag::LOW_SPAN
    tag.update_end(range.begin)
  when Contrast::Agent::Assess::Tag::WITHIN
    remove << tag
  when Contrast::Agent::Assess::Tag::WITHOUT
    new_tag = tag.clone
    new_tag.update_start(range.end)
    add << new_tag
    tag.update_end(range.begin)
  when Contrast::Agent::Assess::Tag::HIGH_SPAN
    tag.update_start(range.end)
  end
end

#tracked?Boolean

Is any tag present? Creating Tags is expensive and we check for Tags all the time on untracked things. ALWAYS!!! call this method before checking if an object has tags

Returns:

  • (Boolean)


23
24
25
# File 'lib/contrast/agent/assess/property/tagged.rb', line 23

def tracked?
  instance_variable_defined?(:@_tags) && tags.any?
end